diff options
author | Angelo Salese <salese_corp_ltd@email.it> | 2014-11-20 01:04:54 +0100 |
---|---|---|
committer | Angelo Salese <salese_corp_ltd@email.it> | 2014-11-20 01:04:54 +0100 |
commit | 3216fdb9520dcc982bdad0e4da1bc1d67a1068cb (patch) | |
tree | 52471bfd7c1dfbd90b20fbd2bf214fd9bfbf7070 | |
parent | 98f29dc4a7d220cd6d376d7235372d7a0353305f (diff) | |
parent | cdeac07354416571ff158b72e38f43cc859fcedf (diff) |
Merge branch 'master' of https://github.com/mamedev/mame
-rw-r--r-- | src/emu/cpu/cpu.mak | 20 | ||||
-rw-r--r-- | src/emu/cpu/rsp/rsp.c | 2657 | ||||
-rw-r--r-- | src/emu/cpu/rsp/rsp.h | 259 | ||||
-rw-r--r-- | src/emu/cpu/rsp/rspcp2.c | 2797 | ||||
-rw-r--r-- | src/emu/cpu/rsp/rspcp2.h | 159 | ||||
-rw-r--r-- | src/emu/cpu/rsp/rspcp2d.c | 3796 | ||||
-rw-r--r-- | src/emu/cpu/rsp/rspcp2d.h | 110 | ||||
-rw-r--r-- | src/emu/cpu/rsp/rspcp2s.c | 3633 | ||||
-rw-r--r-- | src/emu/cpu/rsp/rspcp2s.h | 158 | ||||
-rw-r--r-- | src/emu/cpu/rsp/rspdrc.c | 7937 | ||||
-rw-r--r-- | src/mame/drivers/sauro.c | 39 | ||||
-rw-r--r-- | src/mame/mame.lst | 1 |
12 files changed, 10788 insertions, 10778 deletions
diff --git a/src/emu/cpu/cpu.mak b/src/emu/cpu/cpu.mak index e733c15a58b..597ec26fbc7 100644 --- a/src/emu/cpu/cpu.mak +++ b/src/emu/cpu/cpu.mak @@ -1814,18 +1814,34 @@ $(CPUOBJ)/minx/minx.o: $(CPUSRC)/minx/minx.c \ ifneq ($(filter RSP,$(CPUS)),) OBJDIRS += $(CPUOBJ)/rsp -CPUOBJS += $(CPUOBJ)/rsp/rsp.o $(CPUOBJ)/rsp/rspdrc.o $(CPUOBJ)/rsp/rspfe.o $(DRCOBJ) +CPUOBJS += $(CPUOBJ)/rsp/rsp.o $(CPUOBJ)/rsp/rspdrc.o $(CPUOBJ)/rsp/rspfe.o $(CPUOBJ)/rsp/rspcp2.o $(CPUOBJ)/rsp/rspcp2d.o $(DRCOBJ) DASMOBJS += $(CPUOBJ)/rsp/rsp_dasm.o endif $(CPUOBJ)/rsp/rsp.o: $(CPUSRC)/rsp/rsp.c \ - $(CPUSRC)/rsp/rsp.h + $(CPUSRC)/rsp/rsp.h \ + $(CPUSRC)/rsp/rspcp2.c \ + $(CPUSRC)/rsp/rspcp2.h $(CPUOBJ)/rsp/rspdrc.o: $(CPUSRC)/rsp/rspdrc.c \ $(CPUSRC)/rsp/rsp.h \ $(CPUSRC)/rsp/rspfe.h \ $(DRCDEPS) +$(CPUOBJ)/rsp/rspcp2.o: $(CPUSRC)/rsp/rspcp2.c \ + $(CPUSRC)/rsp/rspcp2.h \ + $(CPUSRC)/rsp/rspdrc.c \ + $(CPUSRC)/rsp/rsp.c \ + $(CPUSRC)/rsp/rsp.h + +$(CPUOBJ)/rsp/rspcp2d.o: $(CPUSRC)/rsp/rspcp2d.c \ + $(CPUSRC)/rsp/rspcp2d.h \ + $(CPUSRC)/rsp/rspcp2.c \ + $(CPUSRC)/rsp/rspcp2.h \ + $(CPUSRC)/rsp/rspdrc.c \ + $(CPUSRC)/rsp/rsp.c \ + $(CPUSRC)/rsp/rsp.h + $(CPUOBJ)/rsp/rspfe.o: $(CPUSRC)/rsp/rspfe.c \ $(CPUSRC)/rsp/rspfe.h diff --git a/src/emu/cpu/rsp/rsp.c b/src/emu/cpu/rsp/rsp.c index 3f3715c37e5..0891f04a09f 100644 --- a/src/emu/cpu/rsp/rsp.c +++ b/src/emu/cpu/rsp/rsp.c @@ -7,8 +7,9 @@ #include "emu.h" #include "debugger.h" #include "rsp.h" -#include "rspdiv.h" #include "rspfe.h" +#include "rspcp2.h" +#include "rspcp2d.h" const device_type RSP = &device_creator<rsp_device>; @@ -36,6 +37,10 @@ extern offs_t rsp_dasm_one(char *buffer, offs_t pc, UINT32 op); #define UIMM16 ((UINT16)(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); } @@ -44,32 +49,6 @@ extern offs_t rsp_dasm_one(char *buffer, offs_t pc, UINT32 op); #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 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)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[(x)][(z)]) - -#define ACCUM(x) m_accum[((x))].q -#define ACCUM_H(x) m_accum[((x))].w[3] -#define ACCUM_M(x) m_accum[((x))].w[2] -#define ACCUM_L(x) m_accum[((x))].w[1] -#define ACCUM_LL(x) m_accum[((x))].w[0] - -#define CARRY 0 -#define COMPARE 1 -#define CLIP1 2 -#define ZERO 3 -#define CLIP2 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) @@ -141,28 +120,8 @@ rsp_device::rsp_device(const machine_config &mconfig, const char *tag, device_t , m_write32(NULL) , m_rsp_state(NULL) , m_exec_output(NULL) -#if SIMUL_SIMD - , m_old_reciprocal_res(0) - , m_old_reciprocal_high(0) - , m_old_dp_allowed(0) - , m_scalar_reciprocal_res(0) - , m_scalar_reciprocal_high(0) - , m_scalar_dp_allowed(0) - , m_simd_reciprocal_res(0) - , m_simd_reciprocal_high(0) - , m_simd_dp_allowed(0) -#endif , m_sr(0) , m_step_count(0) -#if USE_SIMD - , m_accum_h(0) - , m_accum_m(0) - , m_accum_l(0) - , m_accum_ll(0) -#endif - , m_reciprocal_res(0) - , m_reciprocal_high(0) - , m_dp_allowed(0) , m_ppc(0) , m_nextpc(0) , m_dmem32(NULL) @@ -179,20 +138,6 @@ rsp_device::rsp_device(const machine_config &mconfig, const char *tag, device_t , m_sp_set_status_func(*this) { m_isdrc = mconfig.options().drc() ? true : false; - memset(m_vres, 0, sizeof(m_vres)); - memset(m_v, 0, sizeof(m_v)); - memset(m_vflag, 0, sizeof(m_vflag)); -#if SIMUL_SIMD - memset(m_old_r, 0, sizeof(m_old_r)); - memset(m_old_dmem, 0, sizeof(m_old_dmem)); - memset(m_scalar_r, 0, sizeof(m_scalar_r)); - memset(m_scalar_dmem, 0, sizeof(m_scalar_dmem)); -#endif -#if USE_SIMD - memset(m_xv, 0, sizeof(m_xv)); - memset(m_xvflag, 0, sizeof(m_xvflag)); -#endif - memset(m_accum, 0, sizeof(m_accum)); } offs_t rsp_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) @@ -201,25 +146,27 @@ offs_t rsp_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *opro return CPU_DISASSEMBLE_NAME( rsp )(this, buffer, pc, oprom, opram, options); } -inline UINT8 rsp_device::READ8(UINT32 address) +UINT8 rsp_device::READ8(UINT32 address) { UINT8 ret; address &= 0xfff; ret = m_program->read_byte(address); + //printf("R8:%08x=%02x\n", address, ret); return ret; } -inline UINT16 rsp_device::READ16(UINT32 address) +UINT16 rsp_device::READ16(UINT32 address) { UINT16 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; } -inline UINT32 rsp_device::READ32(UINT32 address) +UINT32 rsp_device::READ32(UINT32 address) { UINT32 ret; address &= 0xfff; @@ -229,6 +176,7 @@ inline UINT32 rsp_device::READ32(UINT32 address) (m_program->read_byte(address + 2) << 8) | (m_program->read_byte(address + 3) << 0); + //printf("R32:%08x=%08x\n", address, ret); return ret; } @@ -236,6 +184,7 @@ void rsp_device::WRITE8(UINT32 address, UINT8 data) { address &= 0xfff; m_program->write_byte(address, data); + //printf("W8:%08x=%02x\n", address, data); } void rsp_device::WRITE16(UINT32 address, UINT16 data) @@ -244,6 +193,7 @@ void rsp_device::WRITE16(UINT32 address, UINT16 data) 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 address, UINT32 data) @@ -254,6 +204,7 @@ void rsp_device::WRITE32(UINT32 address, UINT32 data) 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); } /*****************************************************************************/ @@ -370,25 +321,21 @@ void rsp_device::device_start() m_direct = &m_program->direct(); resolve_cb(); + if (m_isdrc) + { + m_cop2 = auto_alloc(machine(), rsp_cop2_drc(*this, machine())); + } + else + { + m_cop2 = auto_alloc(machine(), rsp_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_v[regIdx].d[0] = 0; - m_v[regIdx].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(int accumIdx = 0; accumIdx < 8; accumIdx++ ) - { - m_accum[accumIdx].q = 0; } m_sr = RSP_STATUS_HALT; @@ -544,208 +491,14 @@ void rsp_device::state_export(const device_state_entry &entry) void rsp_device::state_string_export(const device_state_entry &entry, astring &string) { - switch (entry.index()) + const int index = entry.index(); + if (index >= RSP_V0 && index <= RSP_V31) { - case STATE_GENFLAGS: - string.printf("%s",""); - break; - -#if USE_SIMD - case RSP_V0: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[ 0], 7), (UINT16)_mm_extract_epi16(m_xv[ 0], 6), (UINT16)_mm_extract_epi16(m_xv[ 0], 5), (UINT16)_mm_extract_epi16(m_xv[ 0], 4), (UINT16)_mm_extract_epi16(m_xv[ 0], 3), (UINT16)_mm_extract_epi16(m_xv[ 0], 2), (UINT16)_mm_extract_epi16(m_xv[ 0], 1), (UINT16)_mm_extract_epi16(m_xv[ 0], 0)); - break; - case RSP_V1: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[ 1], 7), (UINT16)_mm_extract_epi16(m_xv[ 1], 6), (UINT16)_mm_extract_epi16(m_xv[ 1], 5), (UINT16)_mm_extract_epi16(m_xv[ 1], 4), (UINT16)_mm_extract_epi16(m_xv[ 1], 3), (UINT16)_mm_extract_epi16(m_xv[ 1], 2), (UINT16)_mm_extract_epi16(m_xv[ 1], 1), (UINT16)_mm_extract_epi16(m_xv[ 1], 0)); - break; - case RSP_V2: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[ 2], 7), (UINT16)_mm_extract_epi16(m_xv[ 2], 6), (UINT16)_mm_extract_epi16(m_xv[ 2], 5), (UINT16)_mm_extract_epi16(m_xv[ 2], 4), (UINT16)_mm_extract_epi16(m_xv[ 2], 3), (UINT16)_mm_extract_epi16(m_xv[ 2], 2), (UINT16)_mm_extract_epi16(m_xv[ 2], 1), (UINT16)_mm_extract_epi16(m_xv[ 2], 0)); - break; - case RSP_V3: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[ 3], 7), (UINT16)_mm_extract_epi16(m_xv[ 3], 6), (UINT16)_mm_extract_epi16(m_xv[ 3], 5), (UINT16)_mm_extract_epi16(m_xv[ 3], 4), (UINT16)_mm_extract_epi16(m_xv[ 3], 3), (UINT16)_mm_extract_epi16(m_xv[ 3], 2), (UINT16)_mm_extract_epi16(m_xv[ 3], 1), (UINT16)_mm_extract_epi16(m_xv[ 3], 0)); - break; - case RSP_V4: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[ 4], 7), (UINT16)_mm_extract_epi16(m_xv[ 4], 6), (UINT16)_mm_extract_epi16(m_xv[ 4], 5), (UINT16)_mm_extract_epi16(m_xv[ 4], 4), (UINT16)_mm_extract_epi16(m_xv[ 4], 3), (UINT16)_mm_extract_epi16(m_xv[ 4], 2), (UINT16)_mm_extract_epi16(m_xv[ 4], 1), (UINT16)_mm_extract_epi16(m_xv[ 4], 0)); - break; - case RSP_V5: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[ 5], 7), (UINT16)_mm_extract_epi16(m_xv[ 5], 6), (UINT16)_mm_extract_epi16(m_xv[ 5], 5), (UINT16)_mm_extract_epi16(m_xv[ 5], 4), (UINT16)_mm_extract_epi16(m_xv[ 5], 3), (UINT16)_mm_extract_epi16(m_xv[ 5], 2), (UINT16)_mm_extract_epi16(m_xv[ 5], 1), (UINT16)_mm_extract_epi16(m_xv[ 5], 0)); - break; - case RSP_V6: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[ 6], 7), (UINT16)_mm_extract_epi16(m_xv[ 6], 6), (UINT16)_mm_extract_epi16(m_xv[ 6], 5), (UINT16)_mm_extract_epi16(m_xv[ 6], 4), (UINT16)_mm_extract_epi16(m_xv[ 6], 3), (UINT16)_mm_extract_epi16(m_xv[ 6], 2), (UINT16)_mm_extract_epi16(m_xv[ 6], 1), (UINT16)_mm_extract_epi16(m_xv[ 6], 0)); - break; - case RSP_V7: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[ 7], 7), (UINT16)_mm_extract_epi16(m_xv[ 7], 6), (UINT16)_mm_extract_epi16(m_xv[ 7], 5), (UINT16)_mm_extract_epi16(m_xv[ 7], 4), (UINT16)_mm_extract_epi16(m_xv[ 7], 3), (UINT16)_mm_extract_epi16(m_xv[ 7], 2), (UINT16)_mm_extract_epi16(m_xv[ 7], 1), (UINT16)_mm_extract_epi16(m_xv[ 7], 0)); - break; - case RSP_V8: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[ 8], 7), (UINT16)_mm_extract_epi16(m_xv[ 8], 6), (UINT16)_mm_extract_epi16(m_xv[ 8], 5), (UINT16)_mm_extract_epi16(m_xv[ 8], 4), (UINT16)_mm_extract_epi16(m_xv[ 8], 3), (UINT16)_mm_extract_epi16(m_xv[ 8], 2), (UINT16)_mm_extract_epi16(m_xv[ 8], 1), (UINT16)_mm_extract_epi16(m_xv[ 8], 0)); - break; - case RSP_V9: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[ 9], 7), (UINT16)_mm_extract_epi16(m_xv[ 9], 6), (UINT16)_mm_extract_epi16(m_xv[ 9], 5), (UINT16)_mm_extract_epi16(m_xv[ 9], 4), (UINT16)_mm_extract_epi16(m_xv[ 9], 3), (UINT16)_mm_extract_epi16(m_xv[ 9], 2), (UINT16)_mm_extract_epi16(m_xv[ 9], 1), (UINT16)_mm_extract_epi16(m_xv[ 9], 0)); - break; - case RSP_V10: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[10], 7), (UINT16)_mm_extract_epi16(m_xv[10], 6), (UINT16)_mm_extract_epi16(m_xv[10], 5), (UINT16)_mm_extract_epi16(m_xv[10], 4), (UINT16)_mm_extract_epi16(m_xv[10], 3), (UINT16)_mm_extract_epi16(m_xv[10], 2), (UINT16)_mm_extract_epi16(m_xv[10], 1), (UINT16)_mm_extract_epi16(m_xv[10], 0)); - break; - case RSP_V11: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[11], 7), (UINT16)_mm_extract_epi16(m_xv[11], 6), (UINT16)_mm_extract_epi16(m_xv[11], 5), (UINT16)_mm_extract_epi16(m_xv[11], 4), (UINT16)_mm_extract_epi16(m_xv[11], 3), (UINT16)_mm_extract_epi16(m_xv[11], 2), (UINT16)_mm_extract_epi16(m_xv[11], 1), (UINT16)_mm_extract_epi16(m_xv[11], 0)); - break; - case RSP_V12: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[12], 7), (UINT16)_mm_extract_epi16(m_xv[12], 6), (UINT16)_mm_extract_epi16(m_xv[12], 5), (UINT16)_mm_extract_epi16(m_xv[12], 4), (UINT16)_mm_extract_epi16(m_xv[12], 3), (UINT16)_mm_extract_epi16(m_xv[12], 2), (UINT16)_mm_extract_epi16(m_xv[12], 1), (UINT16)_mm_extract_epi16(m_xv[12], 0)); - break; - case RSP_V13: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[13], 7), (UINT16)_mm_extract_epi16(m_xv[13], 6), (UINT16)_mm_extract_epi16(m_xv[13], 5), (UINT16)_mm_extract_epi16(m_xv[13], 4), (UINT16)_mm_extract_epi16(m_xv[13], 3), (UINT16)_mm_extract_epi16(m_xv[13], 2), (UINT16)_mm_extract_epi16(m_xv[13], 1), (UINT16)_mm_extract_epi16(m_xv[13], 0)); - break; - case RSP_V14: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[14], 7), (UINT16)_mm_extract_epi16(m_xv[14], 6), (UINT16)_mm_extract_epi16(m_xv[14], 5), (UINT16)_mm_extract_epi16(m_xv[14], 4), (UINT16)_mm_extract_epi16(m_xv[14], 3), (UINT16)_mm_extract_epi16(m_xv[14], 2), (UINT16)_mm_extract_epi16(m_xv[14], 1), (UINT16)_mm_extract_epi16(m_xv[14], 0)); - break; - case RSP_V15: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[15], 7), (UINT16)_mm_extract_epi16(m_xv[15], 6), (UINT16)_mm_extract_epi16(m_xv[15], 5), (UINT16)_mm_extract_epi16(m_xv[15], 4), (UINT16)_mm_extract_epi16(m_xv[15], 3), (UINT16)_mm_extract_epi16(m_xv[15], 2), (UINT16)_mm_extract_epi16(m_xv[15], 1), (UINT16)_mm_extract_epi16(m_xv[15], 0)); - break; - case RSP_V16: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[16], 7), (UINT16)_mm_extract_epi16(m_xv[16], 6), (UINT16)_mm_extract_epi16(m_xv[16], 5), (UINT16)_mm_extract_epi16(m_xv[16], 4), (UINT16)_mm_extract_epi16(m_xv[16], 3), (UINT16)_mm_extract_epi16(m_xv[16], 2), (UINT16)_mm_extract_epi16(m_xv[16], 1), (UINT16)_mm_extract_epi16(m_xv[16], 0)); - break; - case RSP_V17: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[17], 7), (UINT16)_mm_extract_epi16(m_xv[17], 6), (UINT16)_mm_extract_epi16(m_xv[17], 5), (UINT16)_mm_extract_epi16(m_xv[17], 4), (UINT16)_mm_extract_epi16(m_xv[17], 3), (UINT16)_mm_extract_epi16(m_xv[17], 2), (UINT16)_mm_extract_epi16(m_xv[17], 1), (UINT16)_mm_extract_epi16(m_xv[17], 0)); - break; - case RSP_V18: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[18], 7), (UINT16)_mm_extract_epi16(m_xv[18], 6), (UINT16)_mm_extract_epi16(m_xv[18], 5), (UINT16)_mm_extract_epi16(m_xv[18], 4), (UINT16)_mm_extract_epi16(m_xv[18], 3), (UINT16)_mm_extract_epi16(m_xv[18], 2), (UINT16)_mm_extract_epi16(m_xv[18], 1), (UINT16)_mm_extract_epi16(m_xv[18], 0)); - break; - case RSP_V19: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[19], 7), (UINT16)_mm_extract_epi16(m_xv[19], 6), (UINT16)_mm_extract_epi16(m_xv[19], 5), (UINT16)_mm_extract_epi16(m_xv[19], 4), (UINT16)_mm_extract_epi16(m_xv[19], 3), (UINT16)_mm_extract_epi16(m_xv[19], 2), (UINT16)_mm_extract_epi16(m_xv[19], 1), (UINT16)_mm_extract_epi16(m_xv[19], 0)); - break; - case RSP_V20: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[20], 7), (UINT16)_mm_extract_epi16(m_xv[20], 6), (UINT16)_mm_extract_epi16(m_xv[20], 5), (UINT16)_mm_extract_epi16(m_xv[20], 4), (UINT16)_mm_extract_epi16(m_xv[20], 3), (UINT16)_mm_extract_epi16(m_xv[20], 2), (UINT16)_mm_extract_epi16(m_xv[20], 1), (UINT16)_mm_extract_epi16(m_xv[20], 0)); - break; - case RSP_V21: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[21], 7), (UINT16)_mm_extract_epi16(m_xv[21], 6), (UINT16)_mm_extract_epi16(m_xv[21], 5), (UINT16)_mm_extract_epi16(m_xv[21], 4), (UINT16)_mm_extract_epi16(m_xv[21], 3), (UINT16)_mm_extract_epi16(m_xv[21], 2), (UINT16)_mm_extract_epi16(m_xv[21], 1), (UINT16)_mm_extract_epi16(m_xv[21], 0)); - break; - case RSP_V22: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[22], 7), (UINT16)_mm_extract_epi16(m_xv[22], 6), (UINT16)_mm_extract_epi16(m_xv[22], 5), (UINT16)_mm_extract_epi16(m_xv[22], 4), (UINT16)_mm_extract_epi16(m_xv[22], 3), (UINT16)_mm_extract_epi16(m_xv[22], 2), (UINT16)_mm_extract_epi16(m_xv[22], 1), (UINT16)_mm_extract_epi16(m_xv[22], 0)); - break; - case RSP_V23: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[23], 7), (UINT16)_mm_extract_epi16(m_xv[23], 6), (UINT16)_mm_extract_epi16(m_xv[23], 5), (UINT16)_mm_extract_epi16(m_xv[23], 4), (UINT16)_mm_extract_epi16(m_xv[23], 3), (UINT16)_mm_extract_epi16(m_xv[23], 2), (UINT16)_mm_extract_epi16(m_xv[23], 1), (UINT16)_mm_extract_epi16(m_xv[23], 0)); - break; - case RSP_V24: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[24], 7), (UINT16)_mm_extract_epi16(m_xv[24], 6), (UINT16)_mm_extract_epi16(m_xv[24], 5), (UINT16)_mm_extract_epi16(m_xv[24], 4), (UINT16)_mm_extract_epi16(m_xv[24], 3), (UINT16)_mm_extract_epi16(m_xv[24], 2), (UINT16)_mm_extract_epi16(m_xv[24], 1), (UINT16)_mm_extract_epi16(m_xv[24], 0)); - break; - case RSP_V25: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[25], 7), (UINT16)_mm_extract_epi16(m_xv[25], 6), (UINT16)_mm_extract_epi16(m_xv[25], 5), (UINT16)_mm_extract_epi16(m_xv[25], 4), (UINT16)_mm_extract_epi16(m_xv[25], 3), (UINT16)_mm_extract_epi16(m_xv[25], 2), (UINT16)_mm_extract_epi16(m_xv[25], 1), (UINT16)_mm_extract_epi16(m_xv[25], 0)); - break; - case RSP_V26: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[26], 7), (UINT16)_mm_extract_epi16(m_xv[26], 6), (UINT16)_mm_extract_epi16(m_xv[26], 5), (UINT16)_mm_extract_epi16(m_xv[26], 4), (UINT16)_mm_extract_epi16(m_xv[26], 3), (UINT16)_mm_extract_epi16(m_xv[26], 2), (UINT16)_mm_extract_epi16(m_xv[26], 1), (UINT16)_mm_extract_epi16(m_xv[26], 0)); - break; - case RSP_V27: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[27], 7), (UINT16)_mm_extract_epi16(m_xv[27], 6), (UINT16)_mm_extract_epi16(m_xv[27], 5), (UINT16)_mm_extract_epi16(m_xv[27], 4), (UINT16)_mm_extract_epi16(m_xv[27], 3), (UINT16)_mm_extract_epi16(m_xv[27], 2), (UINT16)_mm_extract_epi16(m_xv[27], 1), (UINT16)_mm_extract_epi16(m_xv[27], 0)); - break; - case RSP_V28: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[28], 7), (UINT16)_mm_extract_epi16(m_xv[28], 6), (UINT16)_mm_extract_epi16(m_xv[28], 5), (UINT16)_mm_extract_epi16(m_xv[28], 4), (UINT16)_mm_extract_epi16(m_xv[28], 3), (UINT16)_mm_extract_epi16(m_xv[28], 2), (UINT16)_mm_extract_epi16(m_xv[28], 1), (UINT16)_mm_extract_epi16(m_xv[28], 0)); - break; - case RSP_V29: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[29], 7), (UINT16)_mm_extract_epi16(m_xv[29], 6), (UINT16)_mm_extract_epi16(m_xv[29], 5), (UINT16)_mm_extract_epi16(m_xv[29], 4), (UINT16)_mm_extract_epi16(m_xv[29], 3), (UINT16)_mm_extract_epi16(m_xv[29], 2), (UINT16)_mm_extract_epi16(m_xv[29], 1), (UINT16)_mm_extract_epi16(m_xv[29], 0)); - break; - case RSP_V30: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[30], 7), (UINT16)_mm_extract_epi16(m_xv[30], 6), (UINT16)_mm_extract_epi16(m_xv[30], 5), (UINT16)_mm_extract_epi16(m_xv[30], 4), (UINT16)_mm_extract_epi16(m_xv[30], 3), (UINT16)_mm_extract_epi16(m_xv[30], 2), (UINT16)_mm_extract_epi16(m_xv[30], 1), (UINT16)_mm_extract_epi16(m_xv[30], 0)); - break; - case RSP_V31: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[31], 7), (UINT16)_mm_extract_epi16(m_xv[31], 6), (UINT16)_mm_extract_epi16(m_xv[31], 5), (UINT16)_mm_extract_epi16(m_xv[31], 4), (UINT16)_mm_extract_epi16(m_xv[31], 3), (UINT16)_mm_extract_epi16(m_xv[31], 2), (UINT16)_mm_extract_epi16(m_xv[31], 1), (UINT16)_mm_extract_epi16(m_xv[31], 0)); - break; -#else - case RSP_V0: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S( 0, 0), (UINT16)VREG_S( 0, 1), (UINT16)VREG_S( 0, 2), (UINT16)VREG_S( 0, 3), (UINT16)VREG_S( 0, 4), (UINT16)VREG_S( 0, 5), (UINT16)VREG_S( 0, 6), (UINT16)VREG_S( 0, 7)); - break; - case RSP_V1: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S( 1, 0), (UINT16)VREG_S( 1, 1), (UINT16)VREG_S( 1, 2), (UINT16)VREG_S( 1, 3), (UINT16)VREG_S( 1, 4), (UINT16)VREG_S( 1, 5), (UINT16)VREG_S( 1, 6), (UINT16)VREG_S( 1, 7)); - break; - case RSP_V2: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S( 2, 0), (UINT16)VREG_S( 2, 1), (UINT16)VREG_S( 2, 2), (UINT16)VREG_S( 2, 3), (UINT16)VREG_S( 2, 4), (UINT16)VREG_S( 2, 5), (UINT16)VREG_S( 2, 6), (UINT16)VREG_S( 2, 7)); - break; - case RSP_V3: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S( 3, 0), (UINT16)VREG_S( 3, 1), (UINT16)VREG_S( 3, 2), (UINT16)VREG_S( 3, 3), (UINT16)VREG_S( 3, 4), (UINT16)VREG_S( 3, 5), (UINT16)VREG_S( 3, 6), (UINT16)VREG_S( 3, 7)); - break; - case RSP_V4: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S( 4, 0), (UINT16)VREG_S( 4, 1), (UINT16)VREG_S( 4, 2), (UINT16)VREG_S( 4, 3), (UINT16)VREG_S( 4, 4), (UINT16)VREG_S( 4, 5), (UINT16)VREG_S( 4, 6), (UINT16)VREG_S( 4, 7)); - break; - case RSP_V5: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S( 5, 0), (UINT16)VREG_S( 5, 1), (UINT16)VREG_S( 5, 2), (UINT16)VREG_S( 5, 3), (UINT16)VREG_S( 5, 4), (UINT16)VREG_S( 5, 5), (UINT16)VREG_S( 5, 6), (UINT16)VREG_S( 5, 7)); - break; - case RSP_V6: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S( 6, 0), (UINT16)VREG_S( 6, 1), (UINT16)VREG_S( 6, 2), (UINT16)VREG_S( 6, 3), (UINT16)VREG_S( 6, 4), (UINT16)VREG_S( 6, 5), (UINT16)VREG_S( 6, 6), (UINT16)VREG_S( 6, 7)); - break; - case RSP_V7: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S( 7, 0), (UINT16)VREG_S( 7, 1), (UINT16)VREG_S( 7, 2), (UINT16)VREG_S( 7, 3), (UINT16)VREG_S( 7, 4), (UINT16)VREG_S( 7, 5), (UINT16)VREG_S( 7, 6), (UINT16)VREG_S( 7, 7)); - break; - case RSP_V8: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S( 8, 0), (UINT16)VREG_S( 8, 1), (UINT16)VREG_S( 8, 2), (UINT16)VREG_S( 8, 3), (UINT16)VREG_S( 8, 4), (UINT16)VREG_S( 8, 5), (UINT16)VREG_S( 8, 6), (UINT16)VREG_S( 8, 7)); - break; - case RSP_V9: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S( 9, 0), (UINT16)VREG_S( 9, 1), (UINT16)VREG_S( 9, 2), (UINT16)VREG_S( 9, 3), (UINT16)VREG_S( 9, 4), (UINT16)VREG_S( 9, 5), (UINT16)VREG_S( 9, 6), (UINT16)VREG_S( 9, 7)); - break; - case RSP_V10: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(10, 0), (UINT16)VREG_S(10, 1), (UINT16)VREG_S(10, 2), (UINT16)VREG_S(10, 3), (UINT16)VREG_S(10, 4), (UINT16)VREG_S(10, 5), (UINT16)VREG_S(10, 6), (UINT16)VREG_S(10, 7)); - break; - case RSP_V11: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(11, 0), (UINT16)VREG_S(11, 1), (UINT16)VREG_S(11, 2), (UINT16)VREG_S(11, 3), (UINT16)VREG_S(11, 4), (UINT16)VREG_S(11, 5), (UINT16)VREG_S(11, 6), (UINT16)VREG_S(11, 7)); - break; - case RSP_V12: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(12, 0), (UINT16)VREG_S(12, 1), (UINT16)VREG_S(12, 2), (UINT16)VREG_S(12, 3), (UINT16)VREG_S(12, 4), (UINT16)VREG_S(12, 5), (UINT16)VREG_S(12, 6), (UINT16)VREG_S(12, 7)); - break; - case RSP_V13: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(13, 0), (UINT16)VREG_S(13, 1), (UINT16)VREG_S(13, 2), (UINT16)VREG_S(13, 3), (UINT16)VREG_S(13, 4), (UINT16)VREG_S(13, 5), (UINT16)VREG_S(13, 6), (UINT16)VREG_S(13, 7)); - break; - case RSP_V14: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(14, 0), (UINT16)VREG_S(14, 1), (UINT16)VREG_S(14, 2), (UINT16)VREG_S(14, 3), (UINT16)VREG_S(14, 4), (UINT16)VREG_S(14, 5), (UINT16)VREG_S(14, 6), (UINT16)VREG_S(14, 7)); - break; - case RSP_V15: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(15, 0), (UINT16)VREG_S(15, 1), (UINT16)VREG_S(15, 2), (UINT16)VREG_S(15, 3), (UINT16)VREG_S(15, 4), (UINT16)VREG_S(15, 5), (UINT16)VREG_S(15, 6), (UINT16)VREG_S(15, 7)); - break; - case RSP_V16: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(16, 0), (UINT16)VREG_S(16, 1), (UINT16)VREG_S(16, 2), (UINT16)VREG_S(16, 3), (UINT16)VREG_S(16, 4), (UINT16)VREG_S(16, 5), (UINT16)VREG_S(16, 6), (UINT16)VREG_S(16, 7)); - break; - case RSP_V17: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(17, 0), (UINT16)VREG_S(17, 1), (UINT16)VREG_S(17, 2), (UINT16)VREG_S(17, 3), (UINT16)VREG_S(17, 4), (UINT16)VREG_S(17, 5), (UINT16)VREG_S(17, 6), (UINT16)VREG_S(17, 7)); - break; - case RSP_V18: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(18, 0), (UINT16)VREG_S(18, 1), (UINT16)VREG_S(18, 2), (UINT16)VREG_S(18, 3), (UINT16)VREG_S(18, 4), (UINT16)VREG_S(18, 5), (UINT16)VREG_S(18, 6), (UINT16)VREG_S(18, 7)); - break; - case RSP_V19: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(19, 0), (UINT16)VREG_S(19, 1), (UINT16)VREG_S(19, 2), (UINT16)VREG_S(19, 3), (UINT16)VREG_S(19, 4), (UINT16)VREG_S(19, 5), (UINT16)VREG_S(19, 6), (UINT16)VREG_S(19, 7)); - break; - case RSP_V20: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(20, 0), (UINT16)VREG_S(20, 1), (UINT16)VREG_S(20, 2), (UINT16)VREG_S(20, 3), (UINT16)VREG_S(20, 4), (UINT16)VREG_S(20, 5), (UINT16)VREG_S(20, 6), (UINT16)VREG_S(20, 7)); - break; - case RSP_V21: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(21, 0), (UINT16)VREG_S(21, 1), (UINT16)VREG_S(21, 2), (UINT16)VREG_S(21, 3), (UINT16)VREG_S(21, 4), (UINT16)VREG_S(21, 5), (UINT16)VREG_S(21, 6), (UINT16)VREG_S(21, 7)); - break; - case RSP_V22: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(22, 0), (UINT16)VREG_S(22, 1), (UINT16)VREG_S(22, 2), (UINT16)VREG_S(22, 3), (UINT16)VREG_S(22, 4), (UINT16)VREG_S(22, 5), (UINT16)VREG_S(22, 6), (UINT16)VREG_S(22, 7)); - break; - case RSP_V23: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(23, 0), (UINT16)VREG_S(23, 1), (UINT16)VREG_S(23, 2), (UINT16)VREG_S(23, 3), (UINT16)VREG_S(23, 4), (UINT16)VREG_S(23, 5), (UINT16)VREG_S(23, 6), (UINT16)VREG_S(23, 7)); - break; - case RSP_V24: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(24, 0), (UINT16)VREG_S(24, 1), (UINT16)VREG_S(24, 2), (UINT16)VREG_S(24, 3), (UINT16)VREG_S(24, 4), (UINT16)VREG_S(24, 5), (UINT16)VREG_S(24, 6), (UINT16)VREG_S(24, 7)); - break; - case RSP_V25: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(25, 0), (UINT16)VREG_S(25, 1), (UINT16)VREG_S(25, 2), (UINT16)VREG_S(25, 3), (UINT16)VREG_S(25, 4), (UINT16)VREG_S(25, 5), (UINT16)VREG_S(25, 6), (UINT16)VREG_S(25, 7)); - break; - case RSP_V26: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(26, 0), (UINT16)VREG_S(26, 1), (UINT16)VREG_S(26, 2), (UINT16)VREG_S(26, 3), (UINT16)VREG_S(26, 4), (UINT16)VREG_S(26, 5), (UINT16)VREG_S(26, 6), (UINT16)VREG_S(26, 7)); - break; - case RSP_V27: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(27, 0), (UINT16)VREG_S(27, 1), (UINT16)VREG_S(27, 2), (UINT16)VREG_S(27, 3), (UINT16)VREG_S(27, 4), (UINT16)VREG_S(27, 5), (UINT16)VREG_S(27, 6), (UINT16)VREG_S(27, 7)); - break; - case RSP_V28: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(28, 0), (UINT16)VREG_S(28, 1), (UINT16)VREG_S(28, 2), (UINT16)VREG_S(28, 3), (UINT16)VREG_S(28, 4), (UINT16)VREG_S(28, 5), (UINT16)VREG_S(28, 6), (UINT16)VREG_S(28, 7)); - break; - case RSP_V29: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(29, 0), (UINT16)VREG_S(29, 1), (UINT16)VREG_S(29, 2), (UINT16)VREG_S(29, 3), (UINT16)VREG_S(29, 4), (UINT16)VREG_S(29, 5), (UINT16)VREG_S(29, 6), (UINT16)VREG_S(29, 7)); - break; - case RSP_V30: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(30, 0), (UINT16)VREG_S(30, 1), (UINT16)VREG_S(30, 2), (UINT16)VREG_S(30, 3), (UINT16)VREG_S(30, 4), (UINT16)VREG_S(30, 5), (UINT16)VREG_S(30, 6), (UINT16)VREG_S(30, 7)); - break; - case RSP_V31: - string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(31, 0), (UINT16)VREG_S(31, 1), (UINT16)VREG_S(31, 2), (UINT16)VREG_S(31, 3), (UINT16)VREG_S(31, 4), (UINT16)VREG_S(31, 5), (UINT16)VREG_S(31, 6), (UINT16)VREG_S(31, 7)); - break; -#endif - + m_cop2->state_string_export(index, string); + } + else if (index == STATE_GENFLAGS) + { + string.printf("%s",""); } } @@ -795,2169 +548,24 @@ void rsp_device::device_stop() m_exec_output = NULL; /* clean up the DRC */ - if ( m_drcuml ) + if (m_drcuml) { auto_free(machine(), m_drcuml); } - if (m_drcfe ) + if (m_drcfe) { auto_free(machine(), m_drcfe); } -} - -void rsp_device::device_reset() -{ - m_nextpc = ~0; -} - -void rsp_device::handle_lwc2(UINT32 op) -{ - int i, end; - UINT32 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; - - 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 - - ea = (base) ? m_rsp_state->r[base] + offset : offset; - VREG_B(dest, index) = READ8(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 - - ea = (base) ? m_rsp_state->r[base] + (offset * 2) : (offset * 2); - - end = index + 2; - - for (i=index; i < end; i++) - { - VREG_B(dest, i) = READ8(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 - - ea = (base) ? m_rsp_state->r[base] + (offset * 4) : (offset * 4); - - end = index + 4; - - for (i=index; i < end; i++) - { - VREG_B(dest, i) = READ8(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 - - ea = (base) ? m_rsp_state->r[base] + (offset * 8) : (offset * 8); - - end = index + 8; - - for (i=index; i < end; i++) - { - VREG_B(dest, i) = READ8(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 - - ea = (base) ? 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) = READ8(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 - - ea = (base) ? 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) = READ8(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 - - ea = (base) ? m_rsp_state->r[base] + (offset * 8) : (offset * 8); - - for (i=0; i < 8; i++) - { - VREG_S(dest, i) = READ8(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 - - ea = (base) ? m_rsp_state->r[base] + (offset * 8) : (offset * 8); - - for (i=0; i < 8; i++) - { - VREG_S(dest, i) = READ8(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 - - ea = (base) ? m_rsp_state->r[base] + (offset * 16) : (offset * 16); - - for (i=0; i < 8; i++) - { - VREG_S(dest, i) = READ8(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 - - ea = (base) ? 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) = READ8(ea) << 7; - ea += 4; - } - 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 - - ea = (base) ? m_rsp_state->r[base] + (offset * 16) : (offset * 16); - - // not sure what happens if 16-byte boundary is crossed... - if ((ea & 0xf) > 0) fatalerror("RSP: LWV: 16-byte boundary crossing at %08X, recheck this!\n", m_ppc); - - end = (16 - index) + 16; - - for (i=(16 - index); i < end; i++) - { - VREG_B(dest, i & 0xf) = READ8(ea); - ea += 4; - } - 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 - - int element; - int vs = dest; - int ve = dest + 8; - if (ve > 32) - ve = 32; - - element = 7 - (index >> 1); - - if (index & 1) fatalerror("RSP: LTV: index = %d\n", index); - - ea = (base) ? m_rsp_state->r[base] + (offset * 16) : (offset * 16); - - ea = ((ea + 8) & ~0xf) + (index & 1); - for (i=vs; i < ve; i++) - { - element = ((8 - (index >> 1) + (i-vs)) << 1); - VREG_B(i, (element & 0xf)) = READ8(ea); - VREG_B(i, ((element + 1) & 0xf)) = READ8(ea + 1); - - ea += 2; - } - break; - } - - default: - { - unimplemented_opcode(op); - break; - } - } -} - -void rsp_device::handle_swc2(UINT32 op) -{ - int i, end; - int eaoffset; - UINT32 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; - - 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 - - ea = (base) ? m_rsp_state->r[base] + offset : offset; - WRITE8(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 - - ea = (base) ? m_rsp_state->r[base] + (offset * 2) : (offset * 2); - - end = index + 2; - - for (i=index; i < end; i++) - { - WRITE8(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 - - ea = (base) ? m_rsp_state->r[base] + (offset * 4) : (offset * 4); - - end = index + 4; - - for (i=index; i < end; i++) - { - WRITE8(ea, VREG_B(dest, i)); - ea++; - } - 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 - - ea = (base) ? m_rsp_state->r[base] + (offset * 8) : (offset * 8); - - end = index + 8; - - for (i=index; i < end; i++) - { - WRITE8(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 - - ea = (base) ? m_rsp_state->r[base] + (offset * 16) : (offset * 16); - - end = index + (16 - (ea & 0xf)); - - for (i=index; i < end; i++) - { - WRITE8(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 - - int o; - ea = (base) ? 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++) - { - WRITE8(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 - - ea = (base) ? m_rsp_state->r[base] + (offset * 8) : (offset * 8); - end = index + 8; - - for (i=index; i < end; i++) - { - if ((i & 0xf) < 8) - { - WRITE8(ea, VREG_B(dest, ((i & 0xf) << 1))); - } - else - { - WRITE8(ea, VREG_S(dest, (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 - - ea = (base) ? m_rsp_state->r[base] + (offset * 8) : (offset * 8); - end = index + 8; - - for (i=index; i < end; i++) - { - if ((i & 0xf) < 8) - { - WRITE8(ea, VREG_S(dest, (i & 0x7)) >> 7); - } - else - { - WRITE8(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 - - ea = (base) ? m_rsp_state->r[base] + (offset * 16) : (offset * 16); - - for (i=0; i < 8; i++) - { - UINT8 d = ((VREG_B(dest, ((index + (i << 1) + 0) & 0xf))) << 1) | - ((VREG_B(dest, ((index + (i << 1) + 1) & 0xf))) >> 7); - - WRITE8(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 - - if (index & 0x7) osd_printf_debug("RSP: SFV: index = %d at %08X\n", index, m_ppc); - - ea = (base) ? 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++) - { - WRITE8(ea + (eaoffset & 0xf), VREG_S(dest, 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 - - ea = (base) ? m_rsp_state->r[base] + (offset * 16) : (offset * 16); - - eaoffset = ea & 0xf; - ea &= ~0xf; - - end = index + 16; - - for (i=index; i < end; i++) - { - WRITE8(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 - - int element; - int vs = dest; - int ve = dest + 8; - if (ve > 32) - ve = 32; - - element = 8 - (index >> 1); - - ea = (base) ? m_rsp_state->r[base] + (offset * 16) : (offset * 16); - - eaoffset = (ea & 0xf) + (element * 2); - ea &= ~0xf; - - for (i=vs; i < ve; i++) - { - WRITE16(ea + (eaoffset & 0xf), VREG_S(i, element & 0x7)); - eaoffset += 2; - element++; - } - break; - } - - default: - { - unimplemented_opcode(op); - break; - } - } -} -inline UINT16 rsp_device::SATURATE_ACCUM(int accum, int slice, UINT16 negative, UINT16 positive) -{ - if ((INT16)ACCUM_H(accum) < 0) + if (m_cop2) { - if ((UINT16)(ACCUM_H(accum)) != 0xffff) - { - return negative; - } - else - { - if ((INT16)ACCUM_M(accum) >= 0) - { - return negative; - } - else - { - if (slice == 0) - { - return ACCUM_L(accum); - } - else if (slice == 1) - { - return ACCUM_M(accum); - } - } - } + auto_free(machine(), m_cop2); } - else - { - if ((UINT16)(ACCUM_H(accum)) != 0) - { - return positive; - } - else - { - if ((INT16)ACCUM_M(accum) < 0) - { - return positive; - } - else - { - if (slice == 0) - { - return ACCUM_L(accum); - } - else - { - return ACCUM_M(accum); - } - } - } - } - - return 0; } -inline UINT16 rsp_device::SATURATE_ACCUM1(int accum, UINT16 negative, UINT16 positive) -{ - if ((INT16)ACCUM_H(accum) < 0) - { - if ((UINT16)(ACCUM_H(accum)) != 0xffff) - { - return negative; - } - else - { - if ((INT16)ACCUM_M(accum) >= 0) - { - return negative; - } - else - { - return ACCUM_M(accum); - } - } - } - else - { - if ((UINT16)(ACCUM_H(accum)) != 0) - { - return positive; - } - else - { - if ((INT16)ACCUM_M(accum) < 0) - { - return positive; - } - else - { - return ACCUM_M(accum); - } - } - } -} - -#define WRITEBACK_RESULT() {memcpy(&m_v[VDREG].s[0], &vres[0], 16);} - -void rsp_device::handle_vector_ops(UINT32 op) +void rsp_device::device_reset() { - int i; - UINT32 VS1REG = (op >> 11) & 0x1f; - UINT32 VS2REG = (op >> 16) & 0x1f; - UINT32 VDREG = (op >> 6) & 0x1f; - UINT32 EL = (op >> 21) & 0xf; - INT16 vres[8]; - - // 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 - - for (i=0; i < 8; i++) - { - INT32 s1 = (INT32)(INT16)VREG_S(VS1REG, i); - INT32 s2 = (INT32)(INT16)VREG_S(VS2REG, VEC_EL_2(EL, i)); - - if (s1 == -32768 && s2 == -32768) - { - // overflow - ACCUM_H(i) = 0; - ACCUM_M(i) = -32768; - ACCUM_L(i) = -32768; - vres[i] = 0x7fff; - } - else - { - INT64 r = s1 * s2 * 2; - r += 0x8000; // rounding ? - ACCUM_H(i) = (r < 0) ? 0xffff : 0; // sign-extend to 48-bit - ACCUM_M(i) = (INT16)(r >> 16); - ACCUM_L(i) = (UINT16)(r); - vres[i] = ACCUM_M(i); - } - } - WRITEBACK_RESULT(); - - break; - } - - case 0x01: /* VMULU */ - { - // 31 25 24 20 15 10 5 0 - // ------------------------------------------------------ - // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000001 | - // ------------------------------------------------------ - // - - for (i=0; i < 8; i++) - { - INT32 s1 = (INT32)(INT16)VREG_S(VS1REG, i); - INT32 s2 = (INT32)(INT16)VREG_S(VS2REG, VEC_EL_2(EL, i)); - - INT64 r = s1 * s2 * 2; - r += 0x8000; // rounding ? - - ACCUM_H(i) = (UINT16)(r >> 32); - ACCUM_M(i) = (UINT16)(r >> 16); - ACCUM_L(i) = (UINT16)(r); - - if (r < 0) - { - vres[i] = 0; - } - else if (((INT16)(ACCUM_H(i)) ^ (INT16)(ACCUM_M(i))) < 0) - { - vres[i] = -1; - } - else - { - vres[i] = ACCUM_M(i); - } - } - 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 (i=0; i < 8; i++) - { - UINT32 s1 = (UINT32)(UINT16)VREG_S(VS1REG, i); - UINT32 s2 = (UINT32)(UINT16)VREG_S(VS2REG, VEC_EL_2(EL, i)); - UINT32 r = s1 * s2; - - ACCUM_H(i) = 0; - ACCUM_M(i) = 0; - ACCUM_L(i) = (UINT16)(r >> 16); - - vres[i] = ACCUM_L(i); - } - 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 (i=0; i < 8; i++) - { - INT32 s1 = (INT32)(INT16)VREG_S(VS1REG, i); - INT32 s2 = (UINT16)VREG_S(VS2REG, VEC_EL_2(EL, i)); // not sign-extended - INT32 r = s1 * s2; - - ACCUM_H(i) = (r < 0) ? 0xffff : 0; // sign-extend to 48-bit - ACCUM_M(i) = (INT16)(r >> 16); - ACCUM_L(i) = (UINT16)(r); - - vres[i] = ACCUM_M(i); - } - 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 (i=0; i < 8; i++) - { - INT32 s1 = (UINT16)VREG_S(VS1REG, i); // not sign-extended - INT32 s2 = (INT32)(INT16)VREG_S(VS2REG, VEC_EL_2(EL, i)); - INT32 r = s1 * s2; - - ACCUM_H(i) = (r < 0) ? 0xffff : 0; // sign-extend to 48-bit - ACCUM_M(i) = (INT16)(r >> 16); - ACCUM_L(i) = (UINT16)(r); - - vres[i] = ACCUM_L(i); - } - 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 (i=0; i < 8; i++) - { - INT32 s1 = (INT32)(INT16)VREG_S(VS1REG, i); - INT32 s2 = (INT32)(INT16)VREG_S(VS2REG, VEC_EL_2(EL, i)); - INT32 r = s1 * s2; - - ACCUM_H(i) = (INT16)(r >> 16); - ACCUM_M(i) = (UINT16)(r); - ACCUM_L(i) = 0; - - if (r < -32768) r = -32768; - if (r > 32767) r = 32767; - vres[i] = (INT16)(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 (i=0; i < 8; i++) - { - INT32 s1 = (INT32)(INT16)VREG_S(VS1REG, i); - INT32 s2 = (INT32)(INT16)VREG_S(VS2REG, VEC_EL_2(EL, i)); - INT32 r = s1 * s2; - - UINT64 q = (UINT64)(UINT16)ACCUM_LL(i); - q |= (((UINT64)(UINT16)ACCUM_L(i)) << 16); - q |= (((UINT64)(UINT16)ACCUM_M(i)) << 32); - q |= (((UINT64)(UINT16)ACCUM_H(i)) << 48); - - q += (INT64)(r) << 17; - - ACCUM_LL(i) = (UINT16)q; - ACCUM_L(i) = (UINT16)(q >> 16); - ACCUM_M(i) = (UINT16)(q >> 32); - ACCUM_H(i) = (UINT16)(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 (i = 0; i < 8; i++) - { - INT32 s1 = (INT32)(INT16)VREG_S(VS1REG, i); - INT32 s2 = (INT32)(INT16)VREG_S(VS2REG, VEC_EL_2(EL, i)); - INT32 r1 = s1 * s2; - UINT32 r2 = (UINT16)ACCUM_L(i) + ((UINT16)(r1) * 2); - UINT32 r3 = (UINT16)ACCUM_M(i) + (UINT16)((r1 >> 16) * 2) + (UINT16)(r2 >> 16); - - ACCUM_L(i) = (UINT16)(r2); - ACCUM_M(i) = (UINT16)(r3); - ACCUM_H(i) += (UINT16)(r3 >> 16) + (UINT16)(r1 >> 31); - - if ((INT16)ACCUM_H(i) < 0) - { - vres[i] = 0; - } - else - { - if (ACCUM_H(i) != 0) - { - vres[i] = 0xffffu; - } - else - { - if ((INT16)ACCUM_M(i) < 0) - { - vres[i] = 0xffffu; - } - else - { - vres[i] = ACCUM_M(i); - } - } - } - } - 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 (i = 0; i < 8; i++) - { - UINT32 s1 = (UINT32)(UINT16)VREG_S(VS1REG, i); - UINT32 s2 = (UINT32)(UINT16)VREG_S(VS2REG, VEC_EL_2(EL, i)); - UINT32 r1 = s1 * s2; - UINT32 r2 = (UINT16)ACCUM_L(i) + (r1 >> 16); - UINT32 r3 = (UINT16)ACCUM_M(i) + (r2 >> 16); - - ACCUM_L(i) = (UINT16)(r2); - ACCUM_M(i) = (UINT16)(r3); - ACCUM_H(i) += (INT16)(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 (i=0; i < 8; i++) - { - UINT32 s1 = (INT32)(INT16)VREG_S(VS1REG, i); - UINT32 s2 = (UINT16)VREG_S(VS2REG, VEC_EL_2(EL, i)); // not sign-extended - UINT32 r1 = s1 * s2; - UINT32 r2 = (UINT16)ACCUM_L(i) + (UINT16)(r1); - UINT32 r3 = (UINT16)ACCUM_M(i) + (r1 >> 16) + (r2 >> 16); - - ACCUM_L(i) = (UINT16)(r2); - ACCUM_M(i) = (UINT16)(r3); - ACCUM_H(i) += (UINT16)(r3 >> 16); - if ((INT32)(r1) < 0) - ACCUM_H(i) -= 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 (i=0; i < 8; i++) - { - INT32 s1 = (UINT16)VREG_S(VS1REG, i); // not sign-extended - INT32 s2 = (INT32)(INT16)VREG_S(VS2REG, VEC_EL_2(EL, i)); - - UINT64 q = (UINT64)ACCUM_LL(i); - q |= (((UINT64)ACCUM_L(i)) << 16); - q |= (((UINT64)ACCUM_M(i)) << 32); - q |= (((UINT64)ACCUM_H(i)) << 48); - q += (INT64)(s1*s2) << 16; - - ACCUM_LL(i) = (UINT16)q; - ACCUM_L(i) = (UINT16)(q >> 16); - ACCUM_M(i) = (UINT16)(q >> 32); - ACCUM_H(i) = (UINT16)(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 (i = 0; i < 8; i++) - { - INT32 s1 = (INT32)(INT16)VREG_S(VS1REG, i); - INT32 s2 = (INT32)(INT16)VREG_S(VS2REG, VEC_EL_2(EL, i)); - - INT32 accum = (UINT32)(UINT16)ACCUM_M(i); - accum |= ((UINT32)((UINT16)ACCUM_H(i))) << 16; - accum += s1 * s2; - - ACCUM_H(i) = (UINT16)(accum >> 16); - ACCUM_M(i) = (UINT16)accum; - - vres[i] = SATURATE_ACCUM1(i, 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 (i=0; i < 8; i++) - { - INT32 s1 = (INT32)(INT16)VREG_S(VS1REG, i); - INT32 s2 = (INT32)(INT16)VREG_S(VS2REG, VEC_EL_2(EL, i)); - INT32 r = s1 + s2 + (CARRY_FLAG(i) != 0 ? 1 : 0); - - ACCUM_L(i) = (INT16)(r); - - if (r > 32767) r = 32767; - if (r < -32768) r = -32768; - vres[i] = (INT16)(r); - } - CLEAR_ZERO_FLAGS(); - CLEAR_CARRY_FLAGS(); - 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 (i = 0; i < 8; i++) - { - INT32 s1 = (INT32)(INT16)VREG_S(VS1REG, i); - INT32 s2 = (INT32)(INT16)VREG_S(VS2REG, VEC_EL_2(EL, i)); - INT32 r = s1 - s2 - (CARRY_FLAG(i) != 0 ? 1 : 0); - - ACCUM_L(i) = (INT16)(r); - - if (r > 32767) r = 32767; - if (r < -32768) r = -32768; - - vres[i] = (INT16)(r); - } - CLEAR_ZERO_FLAGS(); - CLEAR_CARRY_FLAGS(); - 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 (i=0; i < 8; i++) - { - INT16 s1 = (INT16)VREG_S(VS1REG, i); - INT16 s2 = (INT16)VREG_S(VS2REG, 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; - } - - ACCUM_L(i) = 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 - - CLEAR_ZERO_FLAGS(); - CLEAR_CARRY_FLAGS(); - - for (i=0; i < 8; i++) - { - INT32 s1 = (UINT32)(UINT16)VREG_S(VS1REG, i); - INT32 s2 = (UINT32)(UINT16)VREG_S(VS2REG, VEC_EL_2(EL, i)); - INT32 r = s1 + s2; - - vres[i] = (INT16)(r); - ACCUM_L(i) = (INT16)(r); - - if (r & 0xffff0000) - { - SET_CARRY_FLAG(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 - - CLEAR_ZERO_FLAGS(); - CLEAR_CARRY_FLAGS(); - - for (i=0; i < 8; i++) - { - INT32 s1 = (UINT32)(UINT16)VREG_S(VS1REG, i); - INT32 s2 = (UINT32)(UINT16)VREG_S(VS2REG, VEC_EL_2(EL, i)); - INT32 r = s1 - s2; - - vres[i] = (INT16)(r); - ACCUM_L(i) = (UINT16)(r); - - if ((UINT16)(r) != 0) - { - SET_ZERO_FLAG(i); - } - if (r & 0xffff0000) - { - SET_CARRY_FLAG(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 (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); - } - 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 - - CLEAR_COMPARE_FLAGS(); - CLEAR_CLIP2_FLAGS(); - - for (i=0; i < 8; i++) - { - INT16 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) - { - vres[i] = s1; - } - else - { - vres[i] = s2; - } - - ACCUM_L(i) = vres[i]; - } - - CLEAR_CARRY_FLAGS(); - CLEAR_ZERO_FLAGS(); - 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 - - CLEAR_COMPARE_FLAGS(); - CLEAR_CLIP2_FLAGS(); - - for (i = 0; i < 8; i++) - { - INT16 s1 = VREG_S(VS1REG, i); - INT16 s2 = VREG_S(VS2REG, VEC_EL_2(EL, i)); - - if ((s1 == s2) && ZERO_FLAG(i) == 0) - { - SET_COMPARE_FLAG(i); - vres[i] = s1; - } - else - { - vres[i] = s2; - } - ACCUM_L(i) = vres[i]; - } - - CLEAR_ZERO_FLAGS(); - CLEAR_CARRY_FLAGS(); - 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 - - CLEAR_COMPARE_FLAGS(); - CLEAR_CLIP2_FLAGS(); - - for (i = 0; i < 8; i++) - { - INT16 s1 = VREG_S(VS1REG, i); - INT16 s2 = VREG_S(VS2REG, VEC_EL_2(EL, i)); - - if (s1 != s2 || ZERO_FLAG(i) != 0) - { - SET_COMPARE_FLAG(i); - vres[i] = s1; - } - else - { - vres[i] = s2; - } - ACCUM_L(i) = vres[i]; - } - - CLEAR_CARRY_FLAGS(); - CLEAR_ZERO_FLAGS(); - 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 - - CLEAR_COMPARE_FLAGS(); - CLEAR_CLIP2_FLAGS(); - - for (i=0; i < 8; i++) - { - INT16 s1 = VREG_S(VS1REG, i); - INT16 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); - vres[i] = s1; - } - else - { - vres[i] = s2; - } - - ACCUM_L(i) = vres[i]; - } - - CLEAR_CARRY_FLAGS(); - CLEAR_ZERO_FLAGS(); - 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 (i = 0; i < 8; i++) - { - INT16 s1 = VREG_S(VS1REG, i); - INT16 s2 = VREG_S(VS2REG, VEC_EL_2(EL, i)); - - if (CARRY_FLAG(i) != 0) - { - if (ZERO_FLAG(i) != 0) - { - if (COMPARE_FLAG(i) != 0) - { - ACCUM_L(i) = -(UINT16)s2; - } - else - { - ACCUM_L(i) = s1; - } - } - else - { - if (CLIP1_FLAG(i) != 0) - { - if (((UINT32)(UINT16)(s1) + (UINT32)(UINT16)(s2)) > 0x10000) - { - - ACCUM_L(i) = s1; - CLEAR_COMPARE_FLAG(i); - } - else - { - ACCUM_L(i) = -((UINT16)s2); - SET_COMPARE_FLAG(i); - } - } - else - { - if (((UINT32)(UINT16)(s1) + (UINT32)(UINT16)(s2)) != 0) - { - ACCUM_L(i) = s1; - CLEAR_COMPARE_FLAG(i); - } - else - { - ACCUM_L(i) = -((UINT16)s2); - SET_COMPARE_FLAG(i); - } - } - } - } - else - { - if (ZERO_FLAG(i) != 0) - { - if (CLIP2_FLAG(i) != 0) - { - ACCUM_L(i) = s2; - } - else - { - ACCUM_L(i) = s1; - } - } - else - { - if (((INT32)(UINT16)s1 - (INT32)(UINT16)s2) >= 0) - { - ACCUM_L(i) = s2; - SET_CLIP2_FLAG(i); - } - else - { - ACCUM_L(i) = s1; - CLEAR_CLIP2_FLAG(i); - } - } - } - - vres[i] = ACCUM_L(i); - } - CLEAR_CARRY_FLAGS(); - CLEAR_ZERO_FLAGS(); - CLEAR_CLIP1_FLAGS(); - WRITEBACK_RESULT(); - break; - } - - case 0x25: /* VCH */ - { - // 31 25 24 20 15 10 5 0 - // ------------------------------------------------------ - // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100101 | - // ------------------------------------------------------ - // - // Vector clip high - - CLEAR_CARRY_FLAGS(); - CLEAR_COMPARE_FLAGS(); - CLEAR_CLIP1_FLAGS(); - CLEAR_ZERO_FLAGS(); - CLEAR_CLIP2_FLAGS(); - UINT32 vce = 0; - - for (i=0; i < 8; i++) - { - INT16 s1 = VREG_S(VS1REG, i); - INT16 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); - vres[i] = -((UINT16)s2); - } - else - { - 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); - vres[i] = s2; - } - else - { - vres[i] = s1; - } - - if ((s1 - s2) != 0) - { - if (s1 != ~s2) - { - SET_ZERO_FLAG(i); - } - } - } - if (vce != 0) - { - SET_CLIP1_FLAG(i); - } - ACCUM_L(i) = 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 - - CLEAR_CARRY_FLAGS(); - CLEAR_COMPARE_FLAGS(); - CLEAR_CLIP1_FLAGS(); - CLEAR_ZERO_FLAGS(); - CLEAR_CLIP2_FLAGS(); - - for (i=0; i < 8; i++) - { - INT16 s1 = VREG_S(VS1REG, i); - INT16 s2 = VREG_S(VS2REG, VEC_EL_2(EL, i)); - - if ((INT16)(s1 ^ s2) < 0) - { - if (s2 < 0) - { - SET_CLIP2_FLAG(i); - } - if ((s1 + s2) <= 0) - { - ACCUM_L(i) = ~((UINT16)s2); - SET_COMPARE_FLAG(i); - } - else - { - ACCUM_L(i) = s1; - } - } - else - { - if (s2 < 0) - { - SET_COMPARE_FLAG(i); - } - if ((s1 - s2) >= 0) - { - ACCUM_L(i) = s2; - SET_CLIP2_FLAG(i); - } - else - { - ACCUM_L(i) = s1; - } - } - - vres[i] = ACCUM_L(i); - } - 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 (i = 0; i < 8; i++) - { - if (COMPARE_FLAG(i) != 0) - { - vres[i] = VREG_S(VS1REG, i); - } - else - { - vres[i] = VREG_S(VS2REG, VEC_EL_2(EL, i)); - } - - ACCUM_L(i) = 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 (i = 0; i < 8; i++) - { - vres[i] = VREG_S(VS1REG, i) & VREG_S(VS2REG, VEC_EL_2(EL, i)); - ACCUM_L(i) = 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 (i = 0; i < 8; i++) - { - vres[i] = ~((VREG_S(VS1REG, i) & VREG_S(VS2REG, VEC_EL_2(EL, i)))); - ACCUM_L(i) = 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 (i = 0; i < 8; i++) - { - vres[i] = VREG_S(VS1REG, i) | VREG_S(VS2REG, VEC_EL_2(EL, i)); - ACCUM_L(i) = 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 (i=0; i < 8; i++) - { - vres[i] = ~((VREG_S(VS1REG, i) | VREG_S(VS2REG, VEC_EL_2(EL, i)))); - ACCUM_L(i) = 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 (i=0; i < 8; i++) - { - vres[i] = VREG_S(VS1REG, i) ^ VREG_S(VS2REG, VEC_EL_2(EL, i)); - ACCUM_L(i) = 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 (i=0; i < 8; i++) - { - vres[i] = ~((VREG_S(VS1REG, i) ^ VREG_S(VS2REG, VEC_EL_2(EL, i)))); - ACCUM_L(i) = vres[i]; - } - WRITEBACK_RESULT(); - break; - } - - case 0x30: /* VRCP */ - { - // 31 25 24 20 15 10 5 0 - // ------------------------------------------------------ - // | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110000 | - // ------------------------------------------------------ - // - // Calculates reciprocal - INT32 shifter = 0; - - INT32 rec = (INT16)(VREG_S(VS2REG, EL & 7)); - INT32 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 address = ((datainput << shifter) & 0x7fc00000) >> 22; - INT32 fetchval = rsp_divtable[address]; - INT32 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)(rec & 0xffff); - - for (i = 0; i < 8; i++) - { - ACCUM_L(i) = VREG_S(VS2REG, 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 shifter = 0; - - INT32 rec = (INT16)VREG_S(VS2REG, EL & 7); - INT32 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 address = ((datainput << shifter) & 0x7fc00000) >> 22; - INT32 fetchval = rsp_divtable[address]; - INT32 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)(rec & 0xffff); - - for (i = 0; i < 8; i++) - { - ACCUM_L(i) = VREG_S(VS2REG, 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 = (VREG_S(VS2REG, EL & 7)) << 16; - m_dp_allowed = 1; - - for (i = 0; i < 8; i++) - { - ACCUM_L(i) = VREG_S(VS2REG, VEC_EL_2(EL, i)); - } - - VREG_S(VDREG, VS1REG & 7) = (INT16)(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 - - VREG_S(VDREG, VS1REG & 7) = VREG_S(VS2REG, EL & 7); - for (i = 0; i < 8; i++) - { - ACCUM_L(i) = VREG_S(VS2REG, VEC_EL_2(EL, 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 shifter = 0; - - INT32 rec = (INT16)(VREG_S(VS2REG, EL & 7)); - INT32 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 address = ((datainput << shifter) & 0x7fc00000) >> 22; - address = ((address | 0x200) & 0x3fe) | (shifter & 1); - - INT32 fetchval = rsp_divtable[address]; - INT32 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)(rec & 0xffff); - - for (i = 0; i < 8; i++) - { - ACCUM_L(i) = VREG_S(VS2REG, 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 shifter = 0; - INT32 rec = (INT16)VREG_S(VS2REG, EL & 7); - INT32 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 address = ((datainput << shifter) & 0x7fc00000) >> 22; - address = ((address | 0x200) & 0x3fe) | (shifter & 1); - - INT32 fetchval = rsp_divtable[address]; - INT32 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)(rec & 0xffff); - - for (i = 0; i < 8; i++) - { - ACCUM_L(i) = VREG_S(VS2REG, 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 = (VREG_S(VS2REG, EL & 7)) << 16; - m_dp_allowed = 1; - - for (i=0; i < 8; i++) - { - ACCUM_L(i) = VREG_S(VS2REG, VEC_EL_2(EL, i)); - } - - VREG_S(VDREG, VS1REG & 7) = (INT16)(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; - } - - default: unimplemented_opcode(op); break; - } + m_nextpc = ~0; } void rsp_device::execute_run() @@ -3009,9 +617,6 @@ void rsp_device::execute_run() { m_sp_set_status_func(0, 0x3, 0xffffffff); m_rsp_state->icount = MIN(m_rsp_state->icount, 1); - - if (LOG_INSTRUCTION_EXECUTION) fprintf(m_exec_output, "\n---------- break ----------\n\n"); - break; } case 0x20: /* ADD */ if (RDREG) RDVAL = (INT32)(RSVAL + RTVAL); break; @@ -3070,173 +675,7 @@ void rsp_device::execute_run() case 0x12: /* COP2 */ { - 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 b1 = VREG_B(RDREG, (el+0) & 0xf); - UINT16 b2 = VREG_B(RDREG, (el+1) & 0xf); - if (RTREG) RTVAL = (INT32)(INT16)((b1 << 8) | (b2)); - break; - } - case 0x02: /* CFC2 */ - { - // 31 25 20 15 10 0 - // ------------------------------------------------ - // | 010010 | 00010 | TTTTT | DDDDD | 00000000000 | - // ------------------------------------------------ - // - - 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: - // 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); - } - } - 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, (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) - { - 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; - } - 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; - } + m_cop2->handle_cop2(op); break; } @@ -3248,8 +687,8 @@ void rsp_device::execute_run() 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 */ handle_lwc2(op); break; - case 0x3a: /* SWC2 */ handle_swc2(op); break; + case 0x32: /* LWC2 */ m_cop2->handle_lwc2(op); break; + case 0x3a: /* SWC2 */ m_cop2->handle_swc2(op); break; default: { @@ -3262,7 +701,6 @@ void rsp_device::execute_run() { int i, l; static UINT32 prev_regs[32]; - static VECTOR_REG prev_vecs[32]; char string[200]; rsp_dasm_one(string, m_ppc, op); @@ -3288,16 +726,7 @@ void rsp_device::execute_run() prev_regs[i] = m_rsp_state->r[i]; } - for (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, - (UINT16)VREG_S(i,0), (UINT16)VREG_S(i,1), (UINT16)VREG_S(i,2), (UINT16)VREG_S(i,3), (UINT16)VREG_S(i,4), (UINT16)VREG_S(i,5), (UINT16)VREG_S(i,6), (UINT16)VREG_S(i,7)); - } - prev_vecs[i].d[0] = m_v[i].d[0]; - prev_vecs[i].d[1] = m_v[i].d[1]; - } + m_cop2->log_instruction_execution(); fprintf(m_exec_output, "\n"); diff --git a/src/emu/cpu/rsp/rsp.h b/src/emu/cpu/rsp/rsp.h index 2219cb8082d..b654c555b02 100644 --- a/src/emu/cpu/rsp/rsp.h +++ b/src/emu/cpu/rsp/rsp.h @@ -16,17 +16,9 @@ #ifndef __RSP_H__ #define __RSP_H__ - #include "cpu/drcfe.h" #include "cpu/drcuml.h" -#define USE_SIMD (0) -#define SIMUL_SIMD (0) - -#if USE_SIMD -#include <tmmintrin.h> -#endif - /*************************************************************************** REGISTER ENUMERATION ***************************************************************************/ @@ -87,10 +79,6 @@ enum #define RDREG ((op >> 11) & 31) #define SHIFT ((op >> 6) & 31) -#define RSVAL (m_rsp_state->r[RSREG]) -#define RTVAL (m_rsp_state->r[RTREG]) -#define RDVAL (m_rsp_state->r[RDREG]) - #define FRREG ((op >> 21) & 31) #define FTREG ((op >> 16) & 31) #define FSREG ((op >> 11) & 31) @@ -123,21 +111,6 @@ enum #define RSPDRC_STRICT_VERIFY 0x0001 /* verify all instructions */ -union VECTOR_REG -{ - UINT64 d[2]; - UINT32 l[4]; - INT16 s[8]; - UINT8 b[16]; -}; - -union ACCUMULATOR_REG -{ - UINT64 q; - UINT32 l[2]; - UINT16 w[4]; -}; - #define MCFG_RSP_DP_REG_R_CB(_devcb) \ devcb = &rsp_device::static_set_dp_reg_r_callback(*device, DEVCB_##_devcb); @@ -155,10 +128,14 @@ union ACCUMULATOR_REG class rsp_frontend; +class rsp_cop2; class rsp_device : public cpu_device { friend class rsp_frontend; + friend class rsp_cop2; + friend class rsp_cop2_drc; + friend class rsp_cop2_simd; public: // construction/destruction @@ -187,149 +164,6 @@ public: void ccfunc_unimplemented_opcode(); void ccfunc_sp_set_status_cb(); void ccfunc_unimplemented(); -#if USE_SIMD - void ccfunc_rsp_lbv_simd(); - void ccfunc_rsp_lsv_simd(); - void ccfunc_rsp_llv_simd(); - void ccfunc_rsp_ldv_simd(); - void ccfunc_rsp_lqv_simd(); - void ccfunc_rsp_lrv_simd(); - void ccfunc_rsp_lpv_simd(); - void ccfunc_rsp_luv_simd(); - void ccfunc_rsp_lhv_simd(); - void ccfunc_rsp_lfv_simd(); - void ccfunc_rsp_lwv_simd(); - void ccfunc_rsp_ltv_simd(); - void ccfunc_rsp_sbv_simd(); - void ccfunc_rsp_ssv_simd(); - void ccfunc_rsp_slv_simd(); - void ccfunc_rsp_sdv_simd(); - void ccfunc_rsp_sqv_simd(); - void ccfunc_rsp_srv_simd(); - void ccfunc_rsp_spv_simd(); - void ccfunc_rsp_suv_simd(); - void ccfunc_rsp_shv_simd(); - void ccfunc_rsp_sfv_simd(); - void ccfunc_rsp_swv_simd(); - void ccfunc_rsp_stv_simd(); - void ccfunc_rsp_vmulf_simd(); - void ccfunc_rsp_vmulu_simd(); - void ccfunc_rsp_vmudl_simd(); - void ccfunc_rsp_vmudm_simd(); - void ccfunc_rsp_vmudn_simd(); - void ccfunc_rsp_vmudh_simd(); - void ccfunc_rsp_vmacf_simd(); - void ccfunc_rsp_vmacu_simd(); - void ccfunc_rsp_vmadl_simd(); - void ccfunc_rsp_vmadm_simd(); - void ccfunc_rsp_vmadn_simd(); - void ccfunc_rsp_vmadh_simd(); - void ccfunc_rsp_vadd_simd(); - void ccfunc_rsp_vsub_simd(); - void ccfunc_rsp_vabs_simd(); - void ccfunc_rsp_vaddc_simd(); - void ccfunc_rsp_vsubc_simd(); - void ccfunc_rsp_vsaw_simd(); - void ccfunc_rsp_vlt_simd(); - void ccfunc_rsp_veq_simd(); - void ccfunc_rsp_vne_simd(); - void ccfunc_rsp_vge_simd(); - void ccfunc_rsp_vcl_simd(); - void ccfunc_rsp_vch_simd(); - void ccfunc_rsp_vcr_simd(); - void ccfunc_rsp_vmrg_simd(); - void ccfunc_rsp_vand_simd(); - void ccfunc_rsp_vnand_simd(); - void ccfunc_rsp_vor_simd(); - void ccfunc_rsp_vnor_simd(); - void ccfunc_rsp_vxor_simd(); - void ccfunc_rsp_vnxor_simd(); - void ccfunc_rsp_vrcp_simd(); - void ccfunc_rsp_vrcpl_simd(); - void ccfunc_rsp_vrcph_simd(); - void ccfunc_rsp_vmov_simd(); - void ccfunc_rsp_vrsql_simd(); - void ccfunc_rsp_vrsqh_simd(); - void ccfunc_mfc2_simd(); - void ccfunc_cfc2_simd(); - void ccfunc_mtc2_simd(); - void ccfunc_ctc2_simd(); -#endif -#if (!USE_SIMD || SIMUL_SIMD) - void ccfunc_rsp_lbv_scalar(); - void ccfunc_rsp_lsv_scalar(); - void ccfunc_rsp_llv_scalar(); - void ccfunc_rsp_ldv_scalar(); - void ccfunc_rsp_lqv_scalar(); - void ccfunc_rsp_lrv_scalar(); - void ccfunc_rsp_lpv_scalar(); - void ccfunc_rsp_luv_scalar(); - void ccfunc_rsp_lhv_scalar(); - void ccfunc_rsp_lfv_scalar(); - void ccfunc_rsp_lwv_scalar(); - void ccfunc_rsp_ltv_scalar(); - void ccfunc_rsp_sbv_scalar(); - void ccfunc_rsp_ssv_scalar(); - void ccfunc_rsp_slv_scalar(); - void ccfunc_rsp_sdv_scalar(); - void ccfunc_rsp_sqv_scalar(); - void ccfunc_rsp_srv_scalar(); - void ccfunc_rsp_spv_scalar(); - void ccfunc_rsp_suv_scalar(); - void ccfunc_rsp_shv_scalar(); - void ccfunc_rsp_sfv_scalar(); - void ccfunc_rsp_swv_scalar(); - void ccfunc_rsp_stv_scalar(); - void ccfunc_rsp_vmulf_scalar(); - void ccfunc_rsp_vmulu_scalar(); - void ccfunc_rsp_vmudl_scalar(); - void ccfunc_rsp_vmudm_scalar(); - void ccfunc_rsp_vmudn_scalar(); - void ccfunc_rsp_vmudh_scalar(); - void ccfunc_rsp_vmacf_scalar(); - void ccfunc_rsp_vmacu_scalar(); - void ccfunc_rsp_vmadl_scalar(); - void ccfunc_rsp_vmadm_scalar(); - void ccfunc_rsp_vmadn_scalar(); - void ccfunc_rsp_vmadh_scalar(); - void ccfunc_rsp_vadd_scalar(); - void ccfunc_rsp_vsub_scalar(); - void ccfunc_rsp_vabs_scalar(); - void ccfunc_rsp_vaddc_scalar(); - void ccfunc_rsp_vsubc_scalar(); - void ccfunc_rsp_vaddb_scalar(); - void ccfunc_rsp_vsaw_scalar(); - void ccfunc_rsp_vlt_scalar(); - void ccfunc_rsp_veq_scalar(); - void ccfunc_rsp_vne_scalar(); - void ccfunc_rsp_vge_scalar(); - void ccfunc_rsp_vcl_scalar(); - void ccfunc_rsp_vch_scalar(); - void ccfunc_rsp_vcr_scalar(); - void ccfunc_rsp_vmrg_scalar(); - void ccfunc_rsp_vand_scalar(); - void ccfunc_rsp_vnand_scalar(); - void ccfunc_rsp_vor_scalar(); - void ccfunc_rsp_vnor_scalar(); - void ccfunc_rsp_vxor_scalar(); - void ccfunc_rsp_vnxor_scalar(); - void ccfunc_rsp_vrcp_scalar(); - void ccfunc_rsp_vrcpl_scalar(); - void ccfunc_rsp_vrcph_scalar(); - void ccfunc_rsp_vmov_scalar(); - void ccfunc_rsp_vrsql_scalar(); - void ccfunc_rsp_vrsqh_scalar(); - void ccfunc_mfc2_scalar(); - void ccfunc_cfc2_scalar(); - void ccfunc_mtc2_scalar(); - void ccfunc_ctc2_scalar(); -#endif - void ccfunc_rsp_vrsq_scalar(); -#if USE_SIMD && SIMUL_SIMD - void ccfunc_backup_regs(); - void ccfunc_restore_regs(); - void ccfunc_verify_regs(); -#endif protected: // device-level overrides @@ -358,6 +192,17 @@ protected: virtual UINT32 disasm_max_opcode_bytes() const { return 4; } virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options); + void unimplemented_opcode(UINT32 op); + + /* internal compiler state */ + struct compiler_state + { + UINT32 cycles; /* accumulated cycles */ + UINT8 checkints; /* need to check interrupts before next instruction */ + UINT8 checksoftints; /* need to check software interrupts before next instruction */ + uml::code_label labelnum; /* index for local labels */ + }; + private: address_space_config m_program_config; @@ -370,17 +215,6 @@ private: void * base; /* base in memory where the RAM lives */ }; - - /* internal compiler state */ - struct compiler_state - { - UINT32 cycles; /* accumulated cycles */ - UINT8 checkints; /* need to check interrupts before next instruction */ - UINT8 checksoftints; /* need to check software interrupts before next instruction */ - uml::code_label labelnum; /* index for local labels */ - }; - - /* core state */ drc_cache m_cache; /* pointer to the DRC code cache */ drcuml_state * m_drcuml; /* DRC UML generator state */ @@ -395,7 +229,6 @@ private: const char * m_format; /* format string for print_debug */ UINT32 m_arg2; /* print_debug argument 3 */ UINT32 m_arg3; /* print_debug argument 4 */ - UINT32 m_vres[8]; /* used for temporary vector results */ /* register mappings */ uml::parameter m_regmap[34]; /* parameter to register mappings for all 32 integer registers */ @@ -425,49 +258,9 @@ private: FILE *m_exec_output; - VECTOR_REG m_v[32]; - UINT16 m_vflag[6][8]; - -#if SIMUL_SIMD - UINT32 m_old_r[35]; - UINT8 m_old_dmem[4096]; - - UINT32 m_scalar_r[35]; - UINT8 m_scalar_dmem[4096]; - - INT32 m_old_reciprocal_res; - UINT32 m_old_reciprocal_high; - INT32 m_old_dp_allowed; - - INT32 m_scalar_reciprocal_res; - UINT32 m_scalar_reciprocal_high; - INT32 m_scalar_dp_allowed; - - INT32 m_simd_reciprocal_res; - UINT32 m_simd_reciprocal_high; - INT32 m_simd_dp_allowed; -#endif - -#if USE_SIMD - // Mirror of v[] for now, to be used in parallel as - // more vector ops are transitioned over - __m128i m_xv[32]; - __m128i m_xvflag[6]; -#endif UINT32 m_sr; UINT32 m_step_count; - ACCUMULATOR_REG m_accum[8]; -#if USE_SIMD - __m128i m_accum_h; - __m128i m_accum_m; - __m128i m_accum_l; - __m128i m_accum_ll; -#endif - INT32 m_reciprocal_res; - UINT32 m_reciprocal_high; - INT32 m_dp_allowed; - UINT32 m_ppc; UINT32 m_nextpc; @@ -476,6 +269,8 @@ protected: direct_read_data *m_direct; private: + rsp_cop2 *m_cop2; + UINT32 *m_dmem32; UINT16 *m_dmem16; UINT8 *m_dmem8; @@ -501,24 +296,6 @@ private: void WRITE32(UINT32 address, UINT32 data); UINT32 get_cop0_reg(int reg); void set_cop0_reg(int reg, UINT32 data); - void unimplemented_opcode(UINT32 op); - void handle_lwc2(UINT32 op); - void handle_swc2(UINT32 op); - UINT16 SATURATE_ACCUM(int accum, int slice, UINT16 negative, UINT16 positive); - UINT16 SATURATE_ACCUM1(int accum, UINT16 negative, UINT16 positive); - void handle_vector_ops(UINT32 op); -#if USE_SIMD - UINT16 VEC_ACCUM_H(int x); - UINT16 VEC_ACCUM_M(int x); - UINT16 VEC_ACCUM_L(int x); - UINT16 VEC_ACCUM_LL(int x); - UINT16 VEC_CARRY_FLAG(const int x); - UINT16 VEC_COMPARE_FLAG(const int x); - UINT16 VEC_CLIP1_FLAG(const int x); - UINT16 VEC_ZERO_FLAG(const int x); - UINT16 VEC_CLIP2_FLAG(const int x); - UINT16 VEC_SATURATE_ACCUM(int accum, int slice, UINT16 negative, UINT16 positive); -#endif void load_fast_iregs(drcuml_block *block); void save_fast_iregs(drcuml_block *block); UINT8 DM_READ8(UINT32 address); @@ -528,8 +305,6 @@ private: void DM_WRITE16(UINT32 address, UINT16 data); void DM_WRITE32(UINT32 address, UINT32 data); void rspcom_init(); - int generate_lwc2(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); - int generate_swc2(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); void execute_run_drc(); void code_flush_cache(); void code_compile_block(offs_t pc); diff --git a/src/emu/cpu/rsp/rspcp2.c b/src/emu/cpu/rsp/rspcp2.c new file mode 100644 index 00000000000..d1124d248ef --- /dev/null +++ b/src/emu/cpu/rsp/rspcp2.c @@ -0,0 +1,2797 @@ +/*************************************************************************** + + rspcp2.c + + Universal machine language-based Nintendo/SGI RSP COP2 emulator. + Written by Harmony of the MESS team. + + Copyright the MESS team. + Released for general non-commercial use under the MAME license + Visit http://mamedev.org for licensing and usage restrictions. + +***************************************************************************/ + +#include "emu.h" +#include "rsp.h" +#include "rspdiv.h" +#include "rspcp2.h" +#include "cpu/drcfe.h" +#include "cpu/drcuml.h" +#include "cpu/drcumlsh.h" + +using namespace uml; + +extern offs_t rsp_dasm_one(char *buffer, offs_t pc, UINT32 op); + +/*************************************************************************** + 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)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)m_accum[x].w[3] +#define ACCUM_M(x) (UINT16)m_accum[x].w[2] +#define ACCUM_L(x) (UINT16)m_accum[x].w[1] +#define ACCUM_LL(x) (UINT16)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]; \ +} + +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 +}; + +rsp_cop2::rsp_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)); +} + +void rsp_cop2::init() +{ + CLEAR_CARRY_FLAGS(); + CLEAR_COMPARE_FLAGS(); + CLEAR_CLIP1_FLAGS(); + CLEAR_ZERO_FLAGS(); + CLEAR_CLIP2_FLAGS(); +} + +void rsp_cop2::start() +{ + for(int regIdx = 0; regIdx < 32; regIdx++ ) + { + m_v[regIdx].d[0] = 0; + m_v[regIdx].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(int accumIdx = 0; accumIdx < 8; accumIdx++ ) + { + m_accum[accumIdx].q = 0; + } +} + +void rsp_cop2::state_string_export(const int index, astring &string) +{ + switch (index) + { + case RSP_V0: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S( 0, 0), (UINT16)VREG_S( 0, 1), (UINT16)VREG_S( 0, 2), (UINT16)VREG_S( 0, 3), (UINT16)VREG_S( 0, 4), (UINT16)VREG_S( 0, 5), (UINT16)VREG_S( 0, 6), (UINT16)VREG_S( 0, 7)); + break; + case RSP_V1: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S( 1, 0), (UINT16)VREG_S( 1, 1), (UINT16)VREG_S( 1, 2), (UINT16)VREG_S( 1, 3), (UINT16)VREG_S( 1, 4), (UINT16)VREG_S( 1, 5), (UINT16)VREG_S( 1, 6), (UINT16)VREG_S( 1, 7)); + break; + case RSP_V2: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S( 2, 0), (UINT16)VREG_S( 2, 1), (UINT16)VREG_S( 2, 2), (UINT16)VREG_S( 2, 3), (UINT16)VREG_S( 2, 4), (UINT16)VREG_S( 2, 5), (UINT16)VREG_S( 2, 6), (UINT16)VREG_S( 2, 7)); + break; + case RSP_V3: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S( 3, 0), (UINT16)VREG_S( 3, 1), (UINT16)VREG_S( 3, 2), (UINT16)VREG_S( 3, 3), (UINT16)VREG_S( 3, 4), (UINT16)VREG_S( 3, 5), (UINT16)VREG_S( 3, 6), (UINT16)VREG_S( 3, 7)); + break; + case RSP_V4: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S( 4, 0), (UINT16)VREG_S( 4, 1), (UINT16)VREG_S( 4, 2), (UINT16)VREG_S( 4, 3), (UINT16)VREG_S( 4, 4), (UINT16)VREG_S( 4, 5), (UINT16)VREG_S( 4, 6), (UINT16)VREG_S( 4, 7)); + break; + case RSP_V5: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S( 5, 0), (UINT16)VREG_S( 5, 1), (UINT16)VREG_S( 5, 2), (UINT16)VREG_S( 5, 3), (UINT16)VREG_S( 5, 4), (UINT16)VREG_S( 5, 5), (UINT16)VREG_S( 5, 6), (UINT16)VREG_S( 5, 7)); + break; + case RSP_V6: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S( 6, 0), (UINT16)VREG_S( 6, 1), (UINT16)VREG_S( 6, 2), (UINT16)VREG_S( 6, 3), (UINT16)VREG_S( 6, 4), (UINT16)VREG_S( 6, 5), (UINT16)VREG_S( 6, 6), (UINT16)VREG_S( 6, 7)); + break; + case RSP_V7: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S( 7, 0), (UINT16)VREG_S( 7, 1), (UINT16)VREG_S( 7, 2), (UINT16)VREG_S( 7, 3), (UINT16)VREG_S( 7, 4), (UINT16)VREG_S( 7, 5), (UINT16)VREG_S( 7, 6), (UINT16)VREG_S( 7, 7)); + break; + case RSP_V8: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S( 8, 0), (UINT16)VREG_S( 8, 1), (UINT16)VREG_S( 8, 2), (UINT16)VREG_S( 8, 3), (UINT16)VREG_S( 8, 4), (UINT16)VREG_S( 8, 5), (UINT16)VREG_S( 8, 6), (UINT16)VREG_S( 8, 7)); + break; + case RSP_V9: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S( 9, 0), (UINT16)VREG_S( 9, 1), (UINT16)VREG_S( 9, 2), (UINT16)VREG_S( 9, 3), (UINT16)VREG_S( 9, 4), (UINT16)VREG_S( 9, 5), (UINT16)VREG_S( 9, 6), (UINT16)VREG_S( 9, 7)); + break; + case RSP_V10: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(10, 0), (UINT16)VREG_S(10, 1), (UINT16)VREG_S(10, 2), (UINT16)VREG_S(10, 3), (UINT16)VREG_S(10, 4), (UINT16)VREG_S(10, 5), (UINT16)VREG_S(10, 6), (UINT16)VREG_S(10, 7)); + break; + case RSP_V11: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(11, 0), (UINT16)VREG_S(11, 1), (UINT16)VREG_S(11, 2), (UINT16)VREG_S(11, 3), (UINT16)VREG_S(11, 4), (UINT16)VREG_S(11, 5), (UINT16)VREG_S(11, 6), (UINT16)VREG_S(11, 7)); + break; + case RSP_V12: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(12, 0), (UINT16)VREG_S(12, 1), (UINT16)VREG_S(12, 2), (UINT16)VREG_S(12, 3), (UINT16)VREG_S(12, 4), (UINT16)VREG_S(12, 5), (UINT16)VREG_S(12, 6), (UINT16)VREG_S(12, 7)); + break; + case RSP_V13: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(13, 0), (UINT16)VREG_S(13, 1), (UINT16)VREG_S(13, 2), (UINT16)VREG_S(13, 3), (UINT16)VREG_S(13, 4), (UINT16)VREG_S(13, 5), (UINT16)VREG_S(13, 6), (UINT16)VREG_S(13, 7)); + break; + case RSP_V14: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(14, 0), (UINT16)VREG_S(14, 1), (UINT16)VREG_S(14, 2), (UINT16)VREG_S(14, 3), (UINT16)VREG_S(14, 4), (UINT16)VREG_S(14, 5), (UINT16)VREG_S(14, 6), (UINT16)VREG_S(14, 7)); + break; + case RSP_V15: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(15, 0), (UINT16)VREG_S(15, 1), (UINT16)VREG_S(15, 2), (UINT16)VREG_S(15, 3), (UINT16)VREG_S(15, 4), (UINT16)VREG_S(15, 5), (UINT16)VREG_S(15, 6), (UINT16)VREG_S(15, 7)); + break; + case RSP_V16: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(16, 0), (UINT16)VREG_S(16, 1), (UINT16)VREG_S(16, 2), (UINT16)VREG_S(16, 3), (UINT16)VREG_S(16, 4), (UINT16)VREG_S(16, 5), (UINT16)VREG_S(16, 6), (UINT16)VREG_S(16, 7)); + break; + case RSP_V17: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(17, 0), (UINT16)VREG_S(17, 1), (UINT16)VREG_S(17, 2), (UINT16)VREG_S(17, 3), (UINT16)VREG_S(17, 4), (UINT16)VREG_S(17, 5), (UINT16)VREG_S(17, 6), (UINT16)VREG_S(17, 7)); + break; + case RSP_V18: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(18, 0), (UINT16)VREG_S(18, 1), (UINT16)VREG_S(18, 2), (UINT16)VREG_S(18, 3), (UINT16)VREG_S(18, 4), (UINT16)VREG_S(18, 5), (UINT16)VREG_S(18, 6), (UINT16)VREG_S(18, 7)); + break; + case RSP_V19: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(19, 0), (UINT16)VREG_S(19, 1), (UINT16)VREG_S(19, 2), (UINT16)VREG_S(19, 3), (UINT16)VREG_S(19, 4), (UINT16)VREG_S(19, 5), (UINT16)VREG_S(19, 6), (UINT16)VREG_S(19, 7)); + break; + case RSP_V20: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(20, 0), (UINT16)VREG_S(20, 1), (UINT16)VREG_S(20, 2), (UINT16)VREG_S(20, 3), (UINT16)VREG_S(20, 4), (UINT16)VREG_S(20, 5), (UINT16)VREG_S(20, 6), (UINT16)VREG_S(20, 7)); + break; + case RSP_V21: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(21, 0), (UINT16)VREG_S(21, 1), (UINT16)VREG_S(21, 2), (UINT16)VREG_S(21, 3), (UINT16)VREG_S(21, 4), (UINT16)VREG_S(21, 5), (UINT16)VREG_S(21, 6), (UINT16)VREG_S(21, 7)); + break; + case RSP_V22: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(22, 0), (UINT16)VREG_S(22, 1), (UINT16)VREG_S(22, 2), (UINT16)VREG_S(22, 3), (UINT16)VREG_S(22, 4), (UINT16)VREG_S(22, 5), (UINT16)VREG_S(22, 6), (UINT16)VREG_S(22, 7)); + break; + case RSP_V23: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(23, 0), (UINT16)VREG_S(23, 1), (UINT16)VREG_S(23, 2), (UINT16)VREG_S(23, 3), (UINT16)VREG_S(23, 4), (UINT16)VREG_S(23, 5), (UINT16)VREG_S(23, 6), (UINT16)VREG_S(23, 7)); + break; + case RSP_V24: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(24, 0), (UINT16)VREG_S(24, 1), (UINT16)VREG_S(24, 2), (UINT16)VREG_S(24, 3), (UINT16)VREG_S(24, 4), (UINT16)VREG_S(24, 5), (UINT16)VREG_S(24, 6), (UINT16)VREG_S(24, 7)); + break; + case RSP_V25: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(25, 0), (UINT16)VREG_S(25, 1), (UINT16)VREG_S(25, 2), (UINT16)VREG_S(25, 3), (UINT16)VREG_S(25, 4), (UINT16)VREG_S(25, 5), (UINT16)VREG_S(25, 6), (UINT16)VREG_S(25, 7)); + break; + case RSP_V26: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(26, 0), (UINT16)VREG_S(26, 1), (UINT16)VREG_S(26, 2), (UINT16)VREG_S(26, 3), (UINT16)VREG_S(26, 4), (UINT16)VREG_S(26, 5), (UINT16)VREG_S(26, 6), (UINT16)VREG_S(26, 7)); + break; + case RSP_V27: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(27, 0), (UINT16)VREG_S(27, 1), (UINT16)VREG_S(27, 2), (UINT16)VREG_S(27, 3), (UINT16)VREG_S(27, 4), (UINT16)VREG_S(27, 5), (UINT16)VREG_S(27, 6), (UINT16)VREG_S(27, 7)); + break; + case RSP_V28: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(28, 0), (UINT16)VREG_S(28, 1), (UINT16)VREG_S(28, 2), (UINT16)VREG_S(28, 3), (UINT16)VREG_S(28, 4), (UINT16)VREG_S(28, 5), (UINT16)VREG_S(28, 6), (UINT16)VREG_S(28, 7)); + break; + case RSP_V29: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(29, 0), (UINT16)VREG_S(29, 1), (UINT16)VREG_S(29, 2), (UINT16)VREG_S(29, 3), (UINT16)VREG_S(29, 4), (UINT16)VREG_S(29, 5), (UINT16)VREG_S(29, 6), (UINT16)VREG_S(29, 7)); + break; + case RSP_V30: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(30, 0), (UINT16)VREG_S(30, 1), (UINT16)VREG_S(30, 2), (UINT16)VREG_S(30, 3), (UINT16)VREG_S(30, 4), (UINT16)VREG_S(30, 5), (UINT16)VREG_S(30, 6), (UINT16)VREG_S(30, 7)); + break; + case RSP_V31: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(31, 0), (UINT16)VREG_S(31, 1), (UINT16)VREG_S(31, 2), (UINT16)VREG_S(31, 3), (UINT16)VREG_S(31, 4), (UINT16)VREG_S(31, 5), (UINT16)VREG_S(31, 6), (UINT16)VREG_S(31, 7)); + break; + } +} + +/*************************************************************************** + Vector Load Instructions +***************************************************************************/ + +void rsp_cop2::handle_lwc2(UINT32 op) +{ + int i, end; + UINT32 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; + + 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 + + ea = (base) ? m_rsp.m_rsp_state->r[base] + offset : offset; + VREG_B(dest, index) = m_rsp.READ8(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 + + 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++; + } + 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 + + 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++; + } + 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 + + 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++; + } + 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 + + 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++; + } + 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 + + 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++; + } + 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 + + 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; + } + 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 + + 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; + } + 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 + + 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; + } + 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 + + 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; + } + 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 + + 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; + } + 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 + + int element; + int vs = dest; + int ve = dest + 8; + if (ve > 32) + ve = 32; + + element = 7 - (index >> 1); + + if (index & 1) fatalerror("RSP: LTV: index = %d\n", index); + + ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); + + ea = ((ea + 8) & ~0xf) + (index & 1); + for (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; + } + break; + } + + default: + { + m_rsp.unimplemented_opcode(op); + break; + } + } +} + + +/*************************************************************************** + Vector Store Instructions +***************************************************************************/ + +void rsp_cop2::handle_swc2(UINT32 op) +{ + int i, end; + int eaoffset; + UINT32 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; + + 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 + + ea = (base) ? m_rsp.m_rsp_state->r[base] + offset : offset; + m_rsp.WRITE8(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 + + 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++; + } + 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 + + 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++; + } + 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 + + 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++; + } + 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 + + 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++; + } + 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 + + 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++; + } + break; + } + case 0x06: /* SPV */ + { + // 31 25 20 15 10 6 0 + // -------------------------------------------------- + // | 111010 | BBBBB | TTTTT | 00110 | IIII | Offset | + // -------------------------------------------------- + // + // Stores upper 8 bits of each element + + 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++; + } + break; + } + case 0x07: /* SUV */ + { + // 31 25 20 15 10 6 0 + // -------------------------------------------------- + // | 111010 | BBBBB | TTTTT | 00111 | IIII | Offset | + // -------------------------------------------------- + // + // Stores bits 14-7 of each element + + 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++; + } + 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 + + ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); + + for (i=0; i < 8; i++) + { + UINT8 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; + } + 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 + + 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; + } + 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 + + 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++; + } + 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 + + int element; + int vs = dest; + int ve = dest + 8; + if (ve > 32) + ve = 32; + + element = 8 - (index >> 1); + + ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); + + eaoffset = (ea & 0xf) + (element * 2); + ea &= ~0xf; + + for (i=vs; i < ve; i++) + { + m_rsp.WRITE16(ea + (eaoffset & 0xf), VREG_S(i, element & 0x7)); + eaoffset += 2; + element++; + } + break; + } + + default: + { + m_rsp.unimplemented_opcode(op); + break; + } + } +} + +/*************************************************************************** + Vector Accumulator Helpers +***************************************************************************/ + +inline UINT16 rsp_cop2::SATURATE_ACCUM1(int accum, UINT16 negative, UINT16 positive) +{ +if ((INT16)ACCUM_H(accum) < 0) +{ +if ((UINT16)(ACCUM_H(accum)) != 0xffff) +{ +return negative; +} +else +{ +if ((INT16)ACCUM_M(accum) >= 0) +{ +return negative; +} +else +{ +return ACCUM_M(accum); +} +} +} +else +{ +if ((UINT16)(ACCUM_H(accum)) != 0) +{ +return positive; +} +else +{ +if ((INT16)ACCUM_M(accum) < 0) +{ +return positive; +} +else +{ +return ACCUM_M(accum); +} +} +} +} + +UINT16 rsp_cop2::SATURATE_ACCUM(int accum, int slice, UINT16 negative, UINT16 positive) +{ + if ((INT16)ACCUM_H(accum) < 0) + { + if ((UINT16)(ACCUM_H(accum)) != 0xffff) + { + return negative; + } + else + { + if ((INT16)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)(ACCUM_H(accum)) != 0) + { + return positive; + } + else + { + if ((INT16)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_cop2::handle_vector_ops(UINT32 op) +{ + int i; + + // 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 + + for (i=0; i < 8; i++) + { + INT32 s1 = (INT32)(INT16)VREG_S(VS1REG, i); + INT32 s2 = (INT32)(INT16)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 r = s1 * s2 * 2; + r += 0x8000; // rounding ? + SET_ACCUM_H((r < 0) ? 0xffff : 0, i); // sign-extend to 48-bit + SET_ACCUM_M((INT16)(r >> 16), i); + SET_ACCUM_L((UINT16)(r), i); + m_vres[i] = ACCUM_M(i); + } + } + WRITEBACK_RESULT(); + + break; + } + + case 0x01: /* VMULU */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000001 | + // ------------------------------------------------------ + // + + for (i=0; i < 8; i++) + { + INT32 s1 = (INT32)(INT16)VREG_S(VS1REG, i); + INT32 s2 = (INT32)(INT16)VREG_S(VS2REG, VEC_EL_2(EL, i)); + + INT64 r = s1 * s2 * 2; + r += 0x8000; // rounding ? + + SET_ACCUM_H((UINT16)(r >> 32), i); + SET_ACCUM_M((UINT16)(r >> 16), i); + SET_ACCUM_L((UINT16)(r), i); + + if (r < 0) + { + m_vres[i] = 0; + } + else if (((INT16)(ACCUM_H(i)) ^ (INT16)(ACCUM_M(i))) < 0) + { + m_vres[i] = -1; + } + else + { + m_vres[i] = ACCUM_M(i); + } + } + 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 (i=0; i < 8; i++) + { + UINT32 s1 = (UINT32)(UINT16)VREG_S(VS1REG, i); + UINT32 s2 = (UINT32)(UINT16)VREG_S(VS2REG, VEC_EL_2(EL, i)); + UINT32 r = s1 * s2; + + SET_ACCUM_H(0, i); + SET_ACCUM_M(0, i); + SET_ACCUM_L((UINT16)(r >> 16), i); + + m_vres[i] = ACCUM_L(i); + } + 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 (i=0; i < 8; i++) + { + INT32 s1 = (INT32)(INT16)VREG_S(VS1REG, i); + INT32 s2 = (UINT16)VREG_S(VS2REG, VEC_EL_2(EL, i)); // not sign-extended + INT32 r = s1 * s2; + + SET_ACCUM_H((r < 0) ? 0xffff : 0, i); // sign-extend to 48-bit + SET_ACCUM_M((INT16)(r >> 16), i); + SET_ACCUM_L((UINT16)(r), i); + + m_vres[i] = ACCUM_M(i); + } + 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 (i=0; i < 8; i++) + { + INT32 s1 = (UINT16)VREG_S(VS1REG, i); // not sign-extended + INT32 s2 = (INT32)(INT16)VREG_S(VS2REG, VEC_EL_2(EL, i)); + INT32 r = s1 * s2; + + SET_ACCUM_H((r < 0) ? 0xffff : 0, i); // sign-extend to 48-bit + SET_ACCUM_M((INT16)(r >> 16), i); + SET_ACCUM_L((UINT16)(r), i); + + m_vres[i] = ACCUM_L(i); + } + 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 (i=0; i < 8; i++) + { + INT32 s1 = (INT32)(INT16)VREG_S(VS1REG, i); + INT32 s2 = (INT32)(INT16)VREG_S(VS2REG, VEC_EL_2(EL, i)); + INT32 r = s1 * s2; + + SET_ACCUM_H((INT16)(r >> 16), i); + SET_ACCUM_M((UINT16)(r), i); + SET_ACCUM_L(0, i); + + if (r < -32768) r = -32768; + if (r > 32767) r = 32767; + m_vres[i] = (INT16)(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 (i=0; i < 8; i++) + { + INT32 s1 = (INT32)(INT16)VREG_S(VS1REG, i); + INT32 s2 = (INT32)(INT16)VREG_S(VS2REG, VEC_EL_2(EL, i)); + INT32 r = s1 * s2; + + UINT64 q = (UINT64)(UINT16)ACCUM_LL(i); + q |= (((UINT64)(UINT16)ACCUM_L(i)) << 16); + q |= (((UINT64)(UINT16)ACCUM_M(i)) << 32); + q |= (((UINT64)(UINT16)ACCUM_H(i)) << 48); + + q += (INT64)(r) << 17; + + SET_ACCUM_LL((UINT16)q, i); + SET_ACCUM_L((UINT16)(q >> 16), i); + SET_ACCUM_M((UINT16)(q >> 32), i); + SET_ACCUM_H((UINT16)(q >> 48), i); + + m_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 (i = 0; i < 8; i++) + { + INT32 s1 = (INT32)(INT16)VREG_S(VS1REG, i); + INT32 s2 = (INT32)(INT16)VREG_S(VS2REG, VEC_EL_2(EL, i)); + INT32 r1 = s1 * s2; + UINT32 r2 = (UINT16)ACCUM_L(i) + ((UINT16)(r1) * 2); + UINT32 r3 = (UINT16)ACCUM_M(i) + (UINT16)((r1 >> 16) * 2) + (UINT16)(r2 >> 16); + + SET_ACCUM_L((UINT16)(r2), i); + SET_ACCUM_M((UINT16)(r3), i); + SET_ACCUM_H(ACCUM_H(i) + (UINT16)(r3 >> 16) + (UINT16)(r1 >> 31), i); + + if ((INT16)ACCUM_H(i) < 0) + { + m_vres[i] = 0; + } + else + { + if (ACCUM_H(i) != 0) + { + m_vres[i] = 0xffff; + } + else + { + if ((INT16)ACCUM_M(i) < 0) + { + m_vres[i] = 0xffff; + } + else + { + m_vres[i] = ACCUM_M(i); + } + } + } + } + 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 (i = 0; i < 8; i++) + { + UINT32 s1 = (UINT32)(UINT16)VREG_S(VS1REG, i); + UINT32 s2 = (UINT32)(UINT16)VREG_S(VS2REG, VEC_EL_2(EL, i)); + UINT32 r1 = s1 * s2; + UINT32 r2 = (UINT16)ACCUM_L(i) + (r1 >> 16); + UINT32 r3 = (UINT16)ACCUM_M(i) + (r2 >> 16); + + SET_ACCUM_L((UINT16)(r2), i); + SET_ACCUM_M((UINT16)(r3), i); + SET_ACCUM_H(ACCUM_H(i) + (INT16)(r3 >> 16), i); + + m_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 (i=0; i < 8; i++) + { + UINT32 s1 = (INT32)(INT16)VREG_S(VS1REG, i); + UINT32 s2 = (UINT16)VREG_S(VS2REG, VEC_EL_2(EL, i)); // not sign-extended + UINT32 r1 = s1 * s2; + UINT32 r2 = (UINT16)ACCUM_L(i) + (UINT16)(r1); + UINT32 r3 = (UINT16)ACCUM_M(i) + (r1 >> 16) + (r2 >> 16); + + SET_ACCUM_L((UINT16)(r2), i); + SET_ACCUM_M((UINT16)(r3), i); + SET_ACCUM_H(ACCUM_H(i) + (UINT16)(r3 >> 16), i); + if ((INT32)(r1) < 0) + SET_ACCUM_H(i, ACCUM_H(i) - 1); + + m_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 (i=0; i < 8; i++) + { + INT32 s1 = (UINT16)VREG_S(VS1REG, i); // not sign-extended + INT32 s2 = (INT32)(INT16)VREG_S(VS2REG, VEC_EL_2(EL, i)); + + UINT64 q = (UINT64)ACCUM_LL(i); + q |= (((UINT64)ACCUM_L(i)) << 16); + q |= (((UINT64)ACCUM_M(i)) << 32); + q |= (((UINT64)ACCUM_H(i)) << 48); + q += (INT64)(s1*s2) << 16; + + SET_ACCUM_LL((UINT16)q, i); + SET_ACCUM_L((UINT16)(q >> 16), i); + SET_ACCUM_M((UINT16)(q >> 32), i); + SET_ACCUM_H((UINT16)(q >> 48), i); + + m_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 (i = 0; i < 8; i++) + { + INT32 s1 = (INT32)(INT16)VREG_S(VS1REG, i); + INT32 s2 = (INT32)(INT16)VREG_S(VS2REG, VEC_EL_2(EL, i)); + + INT32 accum = (UINT32)(UINT16)ACCUM_M(i); + accum |= ((UINT32)((UINT16)ACCUM_H(i))) << 16; + accum += s1 * s2; + + SET_ACCUM_H((UINT16)(accum >> 16), i); + SET_ACCUM_M((UINT16)accum, i); + + m_vres[i] = SATURATE_ACCUM1(i, 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 (i=0; i < 8; i++) + { + INT32 s1 = (INT32)(INT16)VREG_S(VS1REG, i); + INT32 s2 = (INT32)(INT16)VREG_S(VS2REG, VEC_EL_2(EL, i)); + INT32 r = s1 + s2 + (CARRY_FLAG(i) != 0 ? 1 : 0); + + SET_ACCUM_L((INT16)(r), i); + + if (r > 32767) r = 32767; + if (r < -32768) r = -32768; + m_vres[i] = (INT16)(r); + } + CLEAR_ZERO_FLAGS(); + CLEAR_CARRY_FLAGS(); + 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 (i = 0; i < 8; i++) + { + INT32 s1 = (INT32)(INT16)VREG_S(VS1REG, i); + INT32 s2 = (INT32)(INT16)VREG_S(VS2REG, VEC_EL_2(EL, i)); + INT32 r = s1 - s2 - (CARRY_FLAG(i) != 0 ? 1 : 0); + + SET_ACCUM_L((INT16)(r), i); + + if (r > 32767) r = 32767; + if (r < -32768) r = -32768; + + m_vres[i] = (INT16)(r); + } + CLEAR_ZERO_FLAGS(); + CLEAR_CARRY_FLAGS(); + 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 (i=0; i < 8; i++) + { + INT16 s1 = (INT16)VREG_S(VS1REG, i); + INT16 s2 = (INT16)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(); + 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 + + CLEAR_ZERO_FLAGS(); + CLEAR_CARRY_FLAGS(); + + for (i=0; i < 8; i++) + { + INT32 s1 = (UINT32)(UINT16)VREG_S(VS1REG, i); + INT32 s2 = (UINT32)(UINT16)VREG_S(VS2REG, VEC_EL_2(EL, i)); + INT32 r = s1 + s2; + + m_vres[i] = (INT16)(r); + SET_ACCUM_L((INT16)(r), i); + + if (r & 0xffff0000) + { + SET_CARRY_FLAG(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 + + CLEAR_ZERO_FLAGS(); + CLEAR_CARRY_FLAGS(); + + for (i=0; i < 8; i++) + { + INT32 s1 = (UINT32)(UINT16)VREG_S(VS1REG, i); + INT32 s2 = (UINT32)(UINT16)VREG_S(VS2REG, VEC_EL_2(EL, i)); + INT32 r = s1 - s2; + + m_vres[i] = (INT16)(r); + SET_ACCUM_L((UINT16)(r), i); + + if ((UINT16)(r) != 0) + { + SET_ZERO_FLAG(i); + } + if (r & 0xffff0000) + { + SET_CARRY_FLAG(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 (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); + } + 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 + + CLEAR_COMPARE_FLAGS(); + CLEAR_CLIP2_FLAGS(); + + for (i=0; i < 8; i++) + { + INT16 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(); + 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 + + CLEAR_COMPARE_FLAGS(); + CLEAR_CLIP2_FLAGS(); + + for (i = 0; i < 8; i++) + { + INT16 s1 = VREG_S(VS1REG, i); + INT16 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(); + 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 + + CLEAR_COMPARE_FLAGS(); + CLEAR_CLIP2_FLAGS(); + + for (i = 0; i < 8; i++) + { + INT16 s1 = VREG_S(VS1REG, i); + INT16 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(); + 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 + + CLEAR_COMPARE_FLAGS(); + CLEAR_CLIP2_FLAGS(); + + for (i=0; i < 8; i++) + { + INT16 s1 = VREG_S(VS1REG, i); + INT16 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(); + break; + } + + case 0x24: /* VCL */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100100 | + // ------------------------------------------------------ + // + // Vector clip low + + for (i = 0; i < 8; i++) + { + INT16 s1 = VREG_S(VS1REG, i); + INT16 s2 = VREG_S(VS2REG, VEC_EL_2(EL, i)); + + if (CARRY_FLAG(i) != 0) + { + if (ZERO_FLAG(i) != 0) + { + if (COMPARE_FLAG(i) != 0) + { + SET_ACCUM_L(-(UINT16)s2, i); + } + else + { + SET_ACCUM_L(s1, i); + } + } + else + { + if (CLIP1_FLAG(i) != 0) + { + if (((UINT32)(UINT16)(s1) + (UINT32)(UINT16)(s2)) > 0x10000) + { + SET_ACCUM_L(s1, i); + CLEAR_COMPARE_FLAG(i); + } + else + { + SET_ACCUM_L(-((UINT16)s2), i); + SET_COMPARE_FLAG(i); + } + } + else + { + if (((UINT32)(UINT16)(s1) + (UINT32)(UINT16)(s2)) != 0) + { + SET_ACCUM_L(s1, i); + CLEAR_COMPARE_FLAG(i); + } + else + { + SET_ACCUM_L(-((UINT16)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)(UINT16)s1 - (INT32)(UINT16)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(); + CLEAR_ZERO_FLAGS(); + CLEAR_CLIP1_FLAGS(); + WRITEBACK_RESULT(); + break; + } + + case 0x25: /* VCH */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100101 | + // ------------------------------------------------------ + // + // Vector clip high + + CLEAR_CARRY_FLAGS(); + CLEAR_COMPARE_FLAGS(); + CLEAR_CLIP1_FLAGS(); + CLEAR_ZERO_FLAGS(); + CLEAR_CLIP2_FLAGS(); + UINT32 vce = 0; + + for (i=0; i < 8; i++) + { + INT16 s1 = VREG_S(VS1REG, i); + INT16 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)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(); + break; + } + + case 0x26: /* VCR */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100110 | + // ------------------------------------------------------ + // + // Vector clip reverse + + CLEAR_CARRY_FLAGS(); + CLEAR_COMPARE_FLAGS(); + CLEAR_CLIP1_FLAGS(); + CLEAR_ZERO_FLAGS(); + CLEAR_CLIP2_FLAGS(); + + for (i=0; i < 8; i++) + { + INT16 s1 = VREG_S(VS1REG, i); + INT16 s2 = VREG_S(VS2REG, VEC_EL_2(EL, i)); + + if ((INT16)(s1 ^ s2) < 0) + { + if (s2 < 0) + { + SET_CLIP2_FLAG(i); + } + if ((s1 + s2) <= 0) + { + SET_ACCUM_L(~((UINT16)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(); + 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 (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(); + 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 (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(); + 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 (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(); + 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 (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(); + 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 (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(); + 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 (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(); + 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 (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(); + break; + } + + case 0x30: /* VRCP */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110000 | + // ------------------------------------------------------ + // + // Calculates reciprocal + INT32 shifter = 0; + + INT32 rec = (INT16)(VREG_S(VS2REG, EL & 7)); + INT32 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 address = ((datainput << shifter) & 0x7fc00000) >> 22; + INT32 fetchval = rsp_divtable[address]; + INT32 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)(rec & 0xffff); + + for (i = 0; i < 8; i++) + { + SET_ACCUM_L(VREG_S(VS2REG, VEC_EL_2(EL, i)), 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 shifter = 0; + + INT32 rec = (INT16)VREG_S(VS2REG, EL & 7); + INT32 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 address = ((datainput << shifter) & 0x7fc00000) >> 22; + INT32 fetchval = rsp_divtable[address]; + INT32 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)(rec & 0xffff); + + for (i = 0; i < 8; i++) + { + SET_ACCUM_L(VREG_S(VS2REG, VEC_EL_2(EL, i)), 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 = (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)(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 + + 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); + } + break; + } + + case 0x34: /* VRSQ */ + { + // 31 25 24 20 15 10 5 0 + // ------------------------------------------------------ + // | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110100 | + // ------------------------------------------------------ + // + // Calculates reciprocal square-root + + INT32 shifter = 0; + + INT32 rec = (INT16)(VREG_S(VS2REG, EL & 7)); + INT32 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 address = ((datainput << shifter) & 0x7fc00000) >> 22; + address = ((address | 0x200) & 0x3fe) | (shifter & 1); + + INT32 fetchval = rsp_divtable[address]; + INT32 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)(rec & 0xffff); + + for (i = 0; i < 8; i++) + { + SET_ACCUM_L(VREG_S(VS2REG, VEC_EL_2(EL, i)), 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 shifter = 0; + INT32 rec = (INT16)VREG_S(VS2REG, EL & 7); + INT32 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 address = ((datainput << shifter) & 0x7fc00000) >> 22; + address = ((address | 0x200) & 0x3fe) | (shifter & 1); + + INT32 fetchval = rsp_divtable[address]; + INT32 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)(rec & 0xffff); + + for (i = 0; i < 8; i++) + { + SET_ACCUM_L(VREG_S(VS2REG, VEC_EL_2(EL, i)), 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 = (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)(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; + } + + default: m_rsp.unimplemented_opcode(op); break; + } +} + +/*************************************************************************** + Vector Flag Reading/Writing +***************************************************************************/ + +void rsp_cop2::handle_cop2(UINT32 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 b1 = VREG_B(RDREG, (el+0) & 0xf); + UINT16 b2 = VREG_B(RDREG, (el+1) & 0xf); + if (RTREG) RTVAL = (INT32)(INT16)((b1 << 8) | (b2)); + break; + } + + case 0x02: /* CFC2 */ + { + // 31 25 20 15 10 0 + // ------------------------------------------------ + // | 010010 | 00010 | TTTTT | DDDDD | 00000000000 | + // ------------------------------------------------ + // + 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: + // 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); + } + } + 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, (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) + { + 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; + } + 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: + m_rsp.unimplemented_opcode(op); + break; + } +} + +inline void rsp_cop2::mfc2() +{ + UINT32 op = m_op; + int el = (op >> 7) & 0xf; + + UINT16 b1 = VREG_B(VS1REG, (el+0) & 0xf); + UINT16 b2 = VREG_B(VS1REG, (el+1) & 0xf); + if (RTREG) RTVAL = (INT32)(INT16)((b1 << 8) | (b2)); +} + +inline void rsp_cop2::cfc2() +{ + UINT32 op = m_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_cop2::mtc2() +{ + UINT32 op = m_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_cop2::ctc2() +{ + UINT32 op = m_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_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)VREG_S(i,0), (UINT16)VREG_S(i,1), (UINT16)VREG_S(i,2), (UINT16)VREG_S(i,3), (UINT16)VREG_S(i,4), (UINT16)VREG_S(i,5), (UINT16)VREG_S(i,6), (UINT16)VREG_S(i,7)); + } + prev_vecs[i].d[0] = m_v[i].d[0]; + prev_vecs[i].d[1] = m_v[i].d[1]; + } +} diff --git a/src/emu/cpu/rsp/rspcp2.h b/src/emu/cpu/rsp/rspcp2.h new file mode 100644 index 00000000000..4dc83f62268 --- /dev/null +++ b/src/emu/cpu/rsp/rspcp2.h @@ -0,0 +1,159 @@ +/*************************************************************************** + + rspcp2.h + + Interface file for Reality Signal Processor (RSP) vector extensions. + + Copyright the MESS team + Released for general non-commercial use under the MAME license + Visit http://mamedev.org for licensing and usage restrictions. + +***************************************************************************/ + +#pragma once + +#ifndef __RSPCP2_H__ +#define __RSPCP2_H__ + +#include "cpu/drcuml.h" +#include "rsp.h" + +#define USE_SIMD (0) +#define SIMUL_SIMD (0) + +union VECTOR_REG +{ + UINT64 d[2]; + UINT32 l[4]; + INT16 s[8]; + UINT8 b[16]; +}; + +union ACCUMULATOR_REG +{ + UINT64 q; + UINT32 l[2]; + UINT16 w[4]; +}; + +struct compiler_state; + +class rsp_cop2 +{ + friend class rsp_device; + +protected: + rsp_cop2(rsp_device &rsp, running_machine &machine); + + virtual void init(); + virtual void start(); + + virtual int generate_cop2(drcuml_block *block, rsp_device::compiler_state *compiler, const opcode_desc *desc) { return TRUE; } + virtual int generate_lwc2(drcuml_block *block, rsp_device::compiler_state *compiler, const opcode_desc *desc) { return TRUE; } + virtual int generate_swc2(drcuml_block *block, rsp_device::compiler_state *compiler, const opcode_desc *desc) { return TRUE; } + + virtual void state_string_export(const int index, astring &string); + +public: + 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 op); + + void log_instruction_execution(); + virtual void cfunc_unimplemented_opcode() { } + +protected: + virtual int generate_vector_opcode(drcuml_block *block, rsp_device::compiler_state *compiler, const opcode_desc *desc) { return TRUE; } + + UINT16 SATURATE_ACCUM(int accum, int slice, UINT16 negative, UINT16 positive); + UINT16 SATURATE_ACCUM1(int accum, UINT16 negative, UINT16 positive); + + UINT32 m_op; + + rsp_device& m_rsp; + running_machine& m_machine; + UINT32 m_vres[8]; /* used for temporary vector results */ + + VECTOR_REG m_v[32]; + + ACCUMULATOR_REG m_accum[8]; + UINT16 m_vflag[6][8]; + + INT32 m_reciprocal_res; + UINT32 m_reciprocal_high; + INT32 m_dp_allowed; + +private: + void handle_lwc2(UINT32 op); + void handle_swc2(UINT32 op); + void handle_vector_ops(UINT32 op); +}; + +#endif /* __RSPCP2_H__ */
\ No newline at end of file diff --git a/src/emu/cpu/rsp/rspcp2d.c b/src/emu/cpu/rsp/rspcp2d.c new file mode 100644 index 00000000000..c0bee5b11b1 --- /dev/null +++ b/src/emu/cpu/rsp/rspcp2d.c @@ -0,0 +1,3796 @@ +/*************************************************************************** + + rspcp2d.c + + Universal machine language-based Nintendo/SGI RSP COP2 emulator. + Written by Harmony of the MESS team. + + Copyright the MESS team. + Released for general non-commercial use under the MAME license + Visit http://mamedev.org for licensing and usage restrictions. + +***************************************************************************/ + +#include "emu.h" +#include "rsp.h" +#include "rspdiv.h" +#include "rspcp2.h" +#include "rspcp2d.h" +#include "cpu/drcfe.h" +#include "cpu/drcuml.h" +#include "cpu/drcumlsh.h" + +using namespace uml; + +extern offs_t rsp_dasm_one(char *buffer, offs_t pc, UINT32 op); + +/*************************************************************************** + 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)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 + +static void cfunc_mfc2(void *param); +static void cfunc_cfc2(void *param); +static void cfunc_mtc2(void *param); +static void cfunc_ctc2(void *param); + +#define ACCUM_H(x) (UINT16)m_accum[x].w[3] +#define ACCUM_M(x) (UINT16)m_accum[x].w[2] +#define ACCUM_L(x) (UINT16)m_accum[x].w[1] +#define ACCUM_LL(x) (UINT16)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 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 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_cop2_drc::cfunc_unimplemented_opcode() +{ + const UINT32 ppc = m_rsp.m_ppc; + if ((m_machine.debug_flags & DEBUG_FLAG_ENABLED) != 0) + { + char string[200]; + rsp_dasm_one(string, ppc, m_op); + osd_printf_debug("%08X: %s\n", ppc, string); + } + fatalerror("RSP: unknown opcode %02X (%08X) at %08X\n", m_op >> 26, m_op, ppc); +} + +static void unimplemented_opcode(void *param) +{ + ((rsp_cop2 *)param)->cfunc_unimplemented_opcode(); +} + +void rsp_cop2_drc::state_string_export(const int index, astring &string) +{ + switch (index) + { + case RSP_V0: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S( 0, 0), (UINT16)VREG_S( 0, 1), (UINT16)VREG_S( 0, 2), (UINT16)VREG_S( 0, 3), (UINT16)VREG_S( 0, 4), (UINT16)VREG_S( 0, 5), (UINT16)VREG_S( 0, 6), (UINT16)VREG_S( 0, 7)); + break; + case RSP_V1: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S( 1, 0), (UINT16)VREG_S( 1, 1), (UINT16)VREG_S( 1, 2), (UINT16)VREG_S( 1, 3), (UINT16)VREG_S( 1, 4), (UINT16)VREG_S( 1, 5), (UINT16)VREG_S( 1, 6), (UINT16)VREG_S( 1, 7)); + break; + case RSP_V2: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S( 2, 0), (UINT16)VREG_S( 2, 1), (UINT16)VREG_S( 2, 2), (UINT16)VREG_S( 2, 3), (UINT16)VREG_S( 2, 4), (UINT16)VREG_S( 2, 5), (UINT16)VREG_S( 2, 6), (UINT16)VREG_S( 2, 7)); + break; + case RSP_V3: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S( 3, 0), (UINT16)VREG_S( 3, 1), (UINT16)VREG_S( 3, 2), (UINT16)VREG_S( 3, 3), (UINT16)VREG_S( 3, 4), (UINT16)VREG_S( 3, 5), (UINT16)VREG_S( 3, 6), (UINT16)VREG_S( 3, 7)); + break; + case RSP_V4: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S( 4, 0), (UINT16)VREG_S( 4, 1), (UINT16)VREG_S( 4, 2), (UINT16)VREG_S( 4, 3), (UINT16)VREG_S( 4, 4), (UINT16)VREG_S( 4, 5), (UINT16)VREG_S( 4, 6), (UINT16)VREG_S( 4, 7)); + break; + case RSP_V5: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S( 5, 0), (UINT16)VREG_S( 5, 1), (UINT16)VREG_S( 5, 2), (UINT16)VREG_S( 5, 3), (UINT16)VREG_S( 5, 4), (UINT16)VREG_S( 5, 5), (UINT16)VREG_S( 5, 6), (UINT16)VREG_S( 5, 7)); + break; + case RSP_V6: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S( 6, 0), (UINT16)VREG_S( 6, 1), (UINT16)VREG_S( 6, 2), (UINT16)VREG_S( 6, 3), (UINT16)VREG_S( 6, 4), (UINT16)VREG_S( 6, 5), (UINT16)VREG_S( 6, 6), (UINT16)VREG_S( 6, 7)); + break; + case RSP_V7: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S( 7, 0), (UINT16)VREG_S( 7, 1), (UINT16)VREG_S( 7, 2), (UINT16)VREG_S( 7, 3), (UINT16)VREG_S( 7, 4), (UINT16)VREG_S( 7, 5), (UINT16)VREG_S( 7, 6), (UINT16)VREG_S( 7, 7)); + break; + case RSP_V8: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S( 8, 0), (UINT16)VREG_S( 8, 1), (UINT16)VREG_S( 8, 2), (UINT16)VREG_S( 8, 3), (UINT16)VREG_S( 8, 4), (UINT16)VREG_S( 8, 5), (UINT16)VREG_S( 8, 6), (UINT16)VREG_S( 8, 7)); + break; + case RSP_V9: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S( 9, 0), (UINT16)VREG_S( 9, 1), (UINT16)VREG_S( 9, 2), (UINT16)VREG_S( 9, 3), (UINT16)VREG_S( 9, 4), (UINT16)VREG_S( 9, 5), (UINT16)VREG_S( 9, 6), (UINT16)VREG_S( 9, 7)); + break; + case RSP_V10: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(10, 0), (UINT16)VREG_S(10, 1), (UINT16)VREG_S(10, 2), (UINT16)VREG_S(10, 3), (UINT16)VREG_S(10, 4), (UINT16)VREG_S(10, 5), (UINT16)VREG_S(10, 6), (UINT16)VREG_S(10, 7)); + break; + case RSP_V11: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(11, 0), (UINT16)VREG_S(11, 1), (UINT16)VREG_S(11, 2), (UINT16)VREG_S(11, 3), (UINT16)VREG_S(11, 4), (UINT16)VREG_S(11, 5), (UINT16)VREG_S(11, 6), (UINT16)VREG_S(11, 7)); + break; + case RSP_V12: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(12, 0), (UINT16)VREG_S(12, 1), (UINT16)VREG_S(12, 2), (UINT16)VREG_S(12, 3), (UINT16)VREG_S(12, 4), (UINT16)VREG_S(12, 5), (UINT16)VREG_S(12, 6), (UINT16)VREG_S(12, 7)); + break; + case RSP_V13: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(13, 0), (UINT16)VREG_S(13, 1), (UINT16)VREG_S(13, 2), (UINT16)VREG_S(13, 3), (UINT16)VREG_S(13, 4), (UINT16)VREG_S(13, 5), (UINT16)VREG_S(13, 6), (UINT16)VREG_S(13, 7)); + break; + case RSP_V14: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(14, 0), (UINT16)VREG_S(14, 1), (UINT16)VREG_S(14, 2), (UINT16)VREG_S(14, 3), (UINT16)VREG_S(14, 4), (UINT16)VREG_S(14, 5), (UINT16)VREG_S(14, 6), (UINT16)VREG_S(14, 7)); + break; + case RSP_V15: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(15, 0), (UINT16)VREG_S(15, 1), (UINT16)VREG_S(15, 2), (UINT16)VREG_S(15, 3), (UINT16)VREG_S(15, 4), (UINT16)VREG_S(15, 5), (UINT16)VREG_S(15, 6), (UINT16)VREG_S(15, 7)); + break; + case RSP_V16: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(16, 0), (UINT16)VREG_S(16, 1), (UINT16)VREG_S(16, 2), (UINT16)VREG_S(16, 3), (UINT16)VREG_S(16, 4), (UINT16)VREG_S(16, 5), (UINT16)VREG_S(16, 6), (UINT16)VREG_S(16, 7)); + break; + case RSP_V17: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(17, 0), (UINT16)VREG_S(17, 1), (UINT16)VREG_S(17, 2), (UINT16)VREG_S(17, 3), (UINT16)VREG_S(17, 4), (UINT16)VREG_S(17, 5), (UINT16)VREG_S(17, 6), (UINT16)VREG_S(17, 7)); + break; + case RSP_V18: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(18, 0), (UINT16)VREG_S(18, 1), (UINT16)VREG_S(18, 2), (UINT16)VREG_S(18, 3), (UINT16)VREG_S(18, 4), (UINT16)VREG_S(18, 5), (UINT16)VREG_S(18, 6), (UINT16)VREG_S(18, 7)); + break; + case RSP_V19: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(19, 0), (UINT16)VREG_S(19, 1), (UINT16)VREG_S(19, 2), (UINT16)VREG_S(19, 3), (UINT16)VREG_S(19, 4), (UINT16)VREG_S(19, 5), (UINT16)VREG_S(19, 6), (UINT16)VREG_S(19, 7)); + break; + case RSP_V20: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(20, 0), (UINT16)VREG_S(20, 1), (UINT16)VREG_S(20, 2), (UINT16)VREG_S(20, 3), (UINT16)VREG_S(20, 4), (UINT16)VREG_S(20, 5), (UINT16)VREG_S(20, 6), (UINT16)VREG_S(20, 7)); + break; + case RSP_V21: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(21, 0), (UINT16)VREG_S(21, 1), (UINT16)VREG_S(21, 2), (UINT16)VREG_S(21, 3), (UINT16)VREG_S(21, 4), (UINT16)VREG_S(21, 5), (UINT16)VREG_S(21, 6), (UINT16)VREG_S(21, 7)); + break; + case RSP_V22: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(22, 0), (UINT16)VREG_S(22, 1), (UINT16)VREG_S(22, 2), (UINT16)VREG_S(22, 3), (UINT16)VREG_S(22, 4), (UINT16)VREG_S(22, 5), (UINT16)VREG_S(22, 6), (UINT16)VREG_S(22, 7)); + break; + case RSP_V23: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(23, 0), (UINT16)VREG_S(23, 1), (UINT16)VREG_S(23, 2), (UINT16)VREG_S(23, 3), (UINT16)VREG_S(23, 4), (UINT16)VREG_S(23, 5), (UINT16)VREG_S(23, 6), (UINT16)VREG_S(23, 7)); + break; + case RSP_V24: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(24, 0), (UINT16)VREG_S(24, 1), (UINT16)VREG_S(24, 2), (UINT16)VREG_S(24, 3), (UINT16)VREG_S(24, 4), (UINT16)VREG_S(24, 5), (UINT16)VREG_S(24, 6), (UINT16)VREG_S(24, 7)); + break; + case RSP_V25: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(25, 0), (UINT16)VREG_S(25, 1), (UINT16)VREG_S(25, 2), (UINT16)VREG_S(25, 3), (UINT16)VREG_S(25, 4), (UINT16)VREG_S(25, 5), (UINT16)VREG_S(25, 6), (UINT16)VREG_S(25, 7)); + break; + case RSP_V26: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(26, 0), (UINT16)VREG_S(26, 1), (UINT16)VREG_S(26, 2), (UINT16)VREG_S(26, 3), (UINT16)VREG_S(26, 4), (UINT16)VREG_S(26, 5), (UINT16)VREG_S(26, 6), (UINT16)VREG_S(26, 7)); + break; + case RSP_V27: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(27, 0), (UINT16)VREG_S(27, 1), (UINT16)VREG_S(27, 2), (UINT16)VREG_S(27, 3), (UINT16)VREG_S(27, 4), (UINT16)VREG_S(27, 5), (UINT16)VREG_S(27, 6), (UINT16)VREG_S(27, 7)); + break; + case RSP_V28: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(28, 0), (UINT16)VREG_S(28, 1), (UINT16)VREG_S(28, 2), (UINT16)VREG_S(28, 3), (UINT16)VREG_S(28, 4), (UINT16)VREG_S(28, 5), (UINT16)VREG_S(28, 6), (UINT16)VREG_S(28, 7)); + break; + case RSP_V29: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(29, 0), (UINT16)VREG_S(29, 1), (UINT16)VREG_S(29, 2), (UINT16)VREG_S(29, 3), (UINT16)VREG_S(29, 4), (UINT16)VREG_S(29, 5), (UINT16)VREG_S(29, 6), (UINT16)VREG_S(29, 7)); + break; + case RSP_V30: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(30, 0), (UINT16)VREG_S(30, 1), (UINT16)VREG_S(30, 2), (UINT16)VREG_S(30, 3), (UINT16)VREG_S(30, 4), (UINT16)VREG_S(30, 5), (UINT16)VREG_S(30, 6), (UINT16)VREG_S(30, 7)); + break; + case RSP_V31: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)VREG_S(31, 0), (UINT16)VREG_S(31, 1), (UINT16)VREG_S(31, 2), (UINT16)VREG_S(31, 3), (UINT16)VREG_S(31, 4), (UINT16)VREG_S(31, 5), (UINT16)VREG_S(31, 6), (UINT16)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 + +inline void rsp_cop2_drc::lbv() +{ + UINT32 op = m_op; + + UINT32 ea = 0; + 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); +} + +static void cfunc_lbv(void *param) +{ + ((rsp_cop2 *)param)->lbv(); +} + + +// LSV +// +// 31 25 20 15 10 6 0 +// -------------------------------------------------- +// | 110010 | BBBBB | TTTTT | 00001 | IIII | Offset | +// -------------------------------------------------- +// +// Loads 2 bytes starting from vector byte index + +inline void rsp_cop2_drc::lsv() +{ + UINT32 op = m_op; + int dest = (op >> 16) & 0x1f; + int base = (op >> 21) & 0x1f; + int index = (op >> 7) & 0xe; + int offset = (op & 0x7f); + if (offset & 0x40) + { + offset |= 0xffffffc0; + } + + UINT32 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++; + } +} + +static void cfunc_lsv(void *param) +{ + ((rsp_cop2 *)param)->lsv(); +} + + +// LLV +// +// 31 25 20 15 10 6 0 +// -------------------------------------------------- +// | 110010 | BBBBB | TTTTT | 00010 | IIII | Offset | +// -------------------------------------------------- +// +// Loads 4 bytes starting from vector byte index + +inline void rsp_cop2_drc::llv() +{ + UINT32 op = m_op; + UINT32 ea = 0; + int dest = (op >> 16) & 0x1f; + int base = (op >> 21) & 0x1f; + int index = (op >> 7) & 0xc; + 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++; + } +} + +static void cfunc_llv(void *param) +{ + ((rsp_cop2 *)param)->llv(); +} + + +// LDV +// +// 31 25 20 15 10 6 0 +// -------------------------------------------------- +// | 110010 | BBBBB | TTTTT | 00011 | IIII | Offset | +// -------------------------------------------------- +// +// Loads 8 bytes starting from vector byte index + +inline void rsp_cop2_drc::ldv() +{ + UINT32 op = m_op; + UINT32 ea = 0; + int dest = (op >> 16) & 0x1f; + int base = (op >> 21) & 0x1f; + int index = (op >> 7) & 0x8; + 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++; + } +} + +static void cfunc_ldv(void *param) +{ + ((rsp_cop2 *)param)->ldv(); +} + + +// LQV +// +// 31 25 20 15 10 6 0 +// -------------------------------------------------- +// | 110010 | BBBBB | TTTTT | 00100 | IIII | Offset | +// -------------------------------------------------- +// +// Loads up to 16 bytes starting from vector byte index + +inline void rsp_cop2_drc::lqv() +{ + UINT32 op = m_op; + int dest = (op >> 16) & 0x1f; + int base = (op >> 21) & 0x1f; + int offset = (op & 0x7f); + if (offset & 0x40) + { + offset |= 0xffffffc0; + } + + UINT32 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++; + } +} + +static void cfunc_lqv(void *param) +{ + ((rsp_cop2 *)param)->lqv(); +} + + +// 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 + +inline void rsp_cop2_drc::lrv() +{ + UINT32 op = m_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 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++; + } +} + +static void cfunc_lrv(void *param) +{ + ((rsp_cop2 *)param)->lrv(); +} + + +// 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 + +inline void rsp_cop2_drc::lpv() +{ + UINT32 op = m_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 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; + } +} + +static void cfunc_lpv(void *param) +{ + ((rsp_cop2 *)param)->lpv(); +} + + +// 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 + +inline void rsp_cop2_drc::luv() +{ + UINT32 op = m_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 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; + } +} + +static void cfunc_luv(void *param) +{ + ((rsp_cop2 *)param)->luv(); +} + + +// 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 + +inline void rsp_cop2_drc::lhv() +{ + UINT32 op = m_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 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; + } +} + +static void cfunc_lhv(void *param) +{ + ((rsp_cop2 *)param)->lhv(); +} + + +// 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 + +inline void rsp_cop2_drc::lfv() +{ + UINT32 op = m_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 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; + } +} + +static void cfunc_lfv(void *param) +{ + ((rsp_cop2 *)param)->lfv(); +} + + +// 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 + +inline void rsp_cop2_drc::lwv() +{ + UINT32 op = m_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 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; + } +} + +static void cfunc_lwv(void *param) +{ + ((rsp_cop2 *)param)->lwv(); +} + + +// 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 + +inline void rsp_cop2_drc::ltv() +{ + UINT32 op = m_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 = 7 - (index >> 1); + + UINT32 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; + } +} + +static void cfunc_ltv(void *param) +{ + ((rsp_cop2 *)param)->ltv(); +} + + +int rsp_cop2_drc::generate_lwc2(drcuml_block *block, rsp_device::compiler_state *compiler, const opcode_desc *desc) +{ + UINT32 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_op), desc->opptr.l[0]); // mov [m_op],desc->opptr.l + UML_CALLC(block, cfunc_lbv, this); + return TRUE; + + case 0x01: /* LSV */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [m_op],desc->opptr.l + UML_CALLC(block, cfunc_lsv, this); + return TRUE; + + case 0x02: /* LLV */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [m_op],desc->opptr.l + UML_CALLC(block, cfunc_llv, this); + return TRUE; + + case 0x03: /* LDV */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [m_op],desc->opptr.l + UML_CALLC(block, cfunc_ldv, this); + return TRUE; + + case 0x04: /* LQV */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [m_op],desc->opptr.l + UML_CALLC(block, cfunc_lqv, this); + return TRUE; + + case 0x05: /* LRV */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [m_op],desc->opptr.l + UML_CALLC(block, cfunc_lrv, this); + return TRUE; + + case 0x06: /* LPV */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [m_op],desc->opptr.l + UML_CALLC(block, cfunc_lpv, this); + return TRUE; + + case 0x07: /* LUV */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [m_op],desc->opptr.l + UML_CALLC(block, cfunc_luv, this); + return TRUE; + + case 0x08: /* LHV */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [m_op],desc->opptr.l + UML_CALLC(block, cfunc_lhv, this); + return TRUE; + + case 0x09: /* LFV */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [m_op],desc->opptr.l + UML_CALLC(block, cfunc_lfv, this); + return TRUE; + + case 0x0a: /* LWV */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [m_op],desc->opptr.l + UML_CALLC(block, cfunc_lwv, this); + return TRUE; + + case 0x0b: /* LTV */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [m_op],desc->opptr.l + UML_CALLC(block, 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 + +inline void rsp_cop2_drc::sbv() +{ + UINT32 op = m_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 ea = (base) ? m_rsp.m_rsp_state->r[base] + offset : offset; + m_rsp.DM_WRITE8(ea, VREG_B(dest, index)); +} + +static void cfunc_sbv(void *param) +{ + ((rsp_cop2 *)param)->sbv(); +} + + +// SSV +// +// 31 25 20 15 10 6 0 +// -------------------------------------------------- +// | 111010 | BBBBB | TTTTT | 00001 | IIII | Offset | +// -------------------------------------------------- +// +// Stores 2 bytes starting from vector byte index + +inline void rsp_cop2_drc::ssv() +{ + UINT32 op = m_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 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++; + } +} + +static void cfunc_ssv(void *param) +{ + ((rsp_cop2 *)param)->ssv(); +} + + +// SLV +// +// 31 25 20 15 10 6 0 +// -------------------------------------------------- +// | 111010 | BBBBB | TTTTT | 00010 | IIII | Offset | +// -------------------------------------------------- +// +// Stores 4 bytes starting from vector byte index + +inline void rsp_cop2_drc::slv() +{ + UINT32 op = m_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 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++; + } +} + +static void cfunc_slv(void *param) +{ + ((rsp_cop2 *)param)->slv(); +} + + +// SDV +// +// 31 25 20 15 10 6 0 +// -------------------------------------------------- +// | 111010 | BBBBB | TTTTT | 00011 | IIII | Offset | +// -------------------------------------------------- +// +// Stores 8 bytes starting from vector byte index + +inline void rsp_cop2_drc::sdv() +{ + UINT32 op = m_op; + int dest = (op >> 16) & 0x1f; + int base = (op >> 21) & 0x1f; + int index = (op >> 7) & 0x8; + int offset = (op & 0x7f); + if (offset & 0x40) + { + offset |= 0xffffffc0; + } + UINT32 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++; + } +} + +static void cfunc_sdv(void *param) +{ + ((rsp_cop2 *)param)->sdv(); +} + + +// 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 + +inline void rsp_cop2_drc::sqv() +{ + UINT32 op = m_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 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++; + } +} + +static void cfunc_sqv(void *param) +{ + ((rsp_cop2 *)param)->sqv(); +} + + +// 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 + +inline void rsp_cop2_drc::srv() +{ + UINT32 op = m_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 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++; + } +} + +static void cfunc_srv(void *param) +{ + ((rsp_cop2 *)param)->srv(); +} + + +// SPV +// +// 31 25 20 15 10 6 0 +// -------------------------------------------------- +// | 111010 | BBBBB | TTTTT | 00110 | IIII | Offset | +// -------------------------------------------------- +// +// Stores upper 8 bits of each element + +inline void rsp_cop2_drc::spv() +{ + UINT32 op = m_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 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++; + } +} + +static void cfunc_spv(void *param) +{ + ((rsp_cop2 *)param)->spv(); +} + + +// SUV +// +// 31 25 20 15 10 6 0 +// -------------------------------------------------- +// | 111010 | BBBBB | TTTTT | 00111 | IIII | Offset | +// -------------------------------------------------- +// +// Stores bits 14-7 of each element + +inline void rsp_cop2_drc::suv() +{ + UINT32 op = m_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 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++; + } +} + +static void cfunc_suv(void *param) +{ + ((rsp_cop2 *)param)->suv(); +} + + +// 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 + +inline void rsp_cop2_drc::shv() +{ + UINT32 op = m_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 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 d = (VREG_B(dest, (element & 0xf)) << 1) | + (VREG_B(dest, ((element + 1) & 0xf)) >> 7); + m_rsp.DM_WRITE8(ea, d); + ea += 2; + } +} + +static void cfunc_shv(void *param) +{ + ((rsp_cop2 *)param)->shv(); +} + + +// 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 + +inline void rsp_cop2_drc::sfv() +{ + UINT32 op = m_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 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; + } +} + +static void cfunc_sfv(void *param) +{ + ((rsp_cop2 *)param)->sfv(); +} + + +// 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 + +inline void rsp_cop2_drc::swv() +{ + UINT32 op = m_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 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++; + } +} + +static void cfunc_swv(void *param) +{ + ((rsp_cop2 *)param)->swv(); +} + + +// 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 + +inline void rsp_cop2_drc::stv() +{ + UINT32 op = m_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 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++; + } +} + +static void cfunc_stv(void *param) +{ + ((rsp_cop2 *)param)->stv(); +} + +int rsp_cop2_drc::generate_swc2(drcuml_block *block, rsp_device::compiler_state *compiler, const opcode_desc *desc) +{ + UINT32 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_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_sbv, this); + return TRUE; + + case 0x01: /* SSV */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_ssv, this); + return TRUE; + + case 0x02: /* SLV */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_slv, this); + return TRUE; + + case 0x03: /* SDV */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_sdv, this); + return TRUE; + + case 0x04: /* SQV */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_sqv, this); + return TRUE; + + case 0x05: /* SRV */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_srv, this); + return TRUE; + + case 0x06: /* SPV */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_spv, this); + return TRUE; + + case 0x07: /* SUV */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_suv, this); + return TRUE; + + case 0x08: /* SHV */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_shv, this); + return TRUE; + + case 0x09: /* SFV */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_sfv, this); + return TRUE; + + case 0x0a: /* SWV */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_swv, this); + return TRUE; + + case 0x0b: /* STV */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, 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 + +inline void rsp_cop2_drc::vmulf() +{ + int op = m_op; + + for (int i = 0; i < 8; i++) + { + UINT16 w1, w2; + GET_VS1(w1, i); + GET_VS2(w2, i); + INT32 s1 = (INT32)(INT16)w1; + INT32 s2 = (INT32)(INT16)w2; + + 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 r = s1 * s2 * 2; + r += 0x8000; // rounding ? + SET_ACCUM_H((r < 0) ? 0xffff : 0, i); + SET_ACCUM_M((INT16)(r >> 16), i); + SET_ACCUM_L((UINT16)(r), i); + m_vres[i] = ACCUM_M(i); + } + } + WRITEBACK_RESULT(); +} + +static void cfunc_vmulf(void *param) +{ + ((rsp_cop2 *)param)->vmulf(); +} + + +// VMULU +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000001 | +// ------------------------------------------------------ +// + +inline void rsp_cop2_drc::vmulu() +{ + int op = m_op; + + for (int i = 0; i < 8; i++) + { + UINT16 w1, w2; + GET_VS1(w1, i); + GET_VS2(w2, i); + INT32 s1 = (INT32)(INT16)w1; + INT32 s2 = (INT32)(INT16)w2; + + INT64 r = s1 * s2 * 2; + r += 0x8000; // rounding ? + + SET_ACCUM_H((UINT16)(r >> 32), i); + SET_ACCUM_M((UINT16)(r >> 16), i); + SET_ACCUM_L((UINT16)(r), i); + + if (r < 0) + { + m_vres[i] = 0; + } + else if (((INT16)(ACCUM_H(i)) ^ (INT16)(ACCUM_M(i))) < 0) + { + m_vres[i] = -1; + } + else + { + m_vres[i] = ACCUM_M(i); + } + } + WRITEBACK_RESULT(); +} + +static void cfunc_vmulu(void *param) +{ + ((rsp_cop2 *)param)->vmulu(); +} + + +// 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 + +inline void rsp_cop2_drc::vmudl() +{ + int op = m_op; + + for (int i = 0; i < 8; i++) + { + UINT16 w1, w2; + GET_VS1(w1, i); + GET_VS2(w2, i); + UINT32 s1 = (UINT32)(UINT16)w1; + UINT32 s2 = (UINT32)(UINT16)w2; + + UINT32 r = s1 * s2; + + SET_ACCUM_H(0, i); + SET_ACCUM_M(0, i); + SET_ACCUM_L((UINT16)(r >> 16), i); + + m_vres[i] = ACCUM_L(i); + } + WRITEBACK_RESULT(); +} + +static void cfunc_vmudl(void *param) +{ + ((rsp_cop2 *)param)->vmudl(); +} + + +// 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 + +inline void rsp_cop2_drc::vmudm() +{ + int op = m_op; + + for (int i = 0; i < 8; i++) + { + UINT16 w1, w2; + GET_VS1(w1, i); + GET_VS2(w2, i); + INT32 s1 = (INT32)(INT16)w1; + INT32 s2 = (UINT16)w2; + + INT32 r = s1 * s2; + + SET_ACCUM_H((r < 0) ? 0xffff : 0, i); // sign-extend to 48-bit + SET_ACCUM_M((INT16)(r >> 16), i); + SET_ACCUM_L((UINT16)r, i); + + m_vres[i] = ACCUM_M(i); + } + WRITEBACK_RESULT(); +} + +static void cfunc_vmudm(void *param) +{ + ((rsp_cop2 *)param)->vmudm(); +} + + +// 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 + +inline void rsp_cop2_drc::vmudn() +{ + int op = m_op; + + for (int i = 0; i < 8; i++) + { + UINT16 w1, w2; + GET_VS1(w1, i); + GET_VS2(w2, i); + INT32 s1 = (UINT16)w1; + INT32 s2 = (INT32)(INT16)w2; + + INT32 r = s1 * s2; + + SET_ACCUM_H((r < 0) ? 0xffff : 0, i); // sign-extend to 48-bit + SET_ACCUM_M((INT16)(r >> 16), i); + SET_ACCUM_L((UINT16)(r), i); + + m_vres[i] = (UINT16)(r); + } + WRITEBACK_RESULT(); +} + +static void cfunc_vmudn(void *param) +{ + ((rsp_cop2 *)param)->vmudn(); +} + + +// 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 + +inline void rsp_cop2_drc::vmudh() +{ + int op = m_op; + + for (int i = 0; i < 8; i++) + { + UINT16 w1, w2; + GET_VS1(w1, i); + GET_VS2(w2, i); + INT32 s1 = (INT32)(INT16)w1; + INT32 s2 = (INT32)(INT16)w2; + + INT32 r = s1 * s2; + + SET_ACCUM_H((INT16)(r >> 16), i); + SET_ACCUM_M((UINT16)(r), i); + SET_ACCUM_L(0, i); + + if (r < -32768) r = -32768; + if (r > 32767) r = 32767; + m_vres[i] = (INT16)(r); + } + WRITEBACK_RESULT(); +} + +static void cfunc_vmudh(void *param) +{ + ((rsp_cop2 *)param)->vmudh(); +} + + +// VMACF +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001000 | +// ------------------------------------------------------ +// + +inline void rsp_cop2_drc::vmacf() +{ + int op = m_op; + + for (int i = 0; i < 8; i++) + { + UINT16 w1, w2; + GET_VS1(w1, i); + GET_VS2(w2, i); + INT32 s1 = (INT32)(INT16)w1; + INT32 s2 = (INT32)(INT16)w2; + + INT32 r = s1 * s2; + + UINT64 q = (UINT64)(UINT16)ACCUM_LL(i); + q |= (((UINT64)(UINT16)ACCUM_L(i)) << 16); + q |= (((UINT64)(UINT16)ACCUM_M(i)) << 32); + q |= (((UINT64)(UINT16)ACCUM_H(i)) << 48); + + q += (INT64)(r) << 17; + SET_ACCUM_LL((UINT16)q, i); + SET_ACCUM_L((UINT16)(q >> 16), i); + SET_ACCUM_M((UINT16)(q >> 32), i); + SET_ACCUM_H((UINT16)(q >> 48), i); + + m_vres[i] = SATURATE_ACCUM(i, 1, 0x8000, 0x7fff); + } + WRITEBACK_RESULT(); +} + +static void cfunc_vmacf(void *param) +{ + ((rsp_cop2 *)param)->vmacf(); +} + + +// VMACU +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001001 | +// ------------------------------------------------------ +// + +inline void rsp_cop2_drc::vmacu() +{ + int op = m_op; + + for (int i = 0; i < 8; i++) + { + UINT16 w1, w2; + GET_VS1(w1, i); + GET_VS2(w2, i); + INT32 s1 = (INT32)(INT16)w1; + INT32 s2 = (INT32)(INT16)w2; + + INT32 r1 = s1 * s2; + UINT32 r2 = (UINT16)ACCUM_L(i) + ((UINT16)(r1) * 2); + UINT32 r3 = (UINT16)ACCUM_M(i) + (UINT16)((r1 >> 16) * 2) + (UINT16)(r2 >> 16); + + SET_ACCUM_L((UINT16)(r2), i); + SET_ACCUM_M((UINT16)(r3), i); + SET_ACCUM_H(ACCUM_H(i) + (UINT16)(r3 >> 16) + (UINT16)(r1 >> 31), i); + + if ((INT16)ACCUM_H(i) < 0) + { + m_vres[i] = 0; + } + else + { + if (ACCUM_H(i) != 0) + { + m_vres[i] = (INT16)0xffff; + } + else + { + if ((INT16)ACCUM_M(i) < 0) + { + m_vres[i] = (INT16)0xffff; + } + else + { + m_vres[i] = ACCUM_M(i); + } + } + } + } + WRITEBACK_RESULT(); +} + +static void cfunc_vmacu(void *param) +{ + ((rsp_cop2 *)param)->vmacu(); +} + + +// 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 + +inline void rsp_cop2_drc::vmadl() +{ + int op = m_op; + + for (int i = 0; i < 8; i++) + { + UINT16 w1, w2; + GET_VS1(w1, i); + GET_VS2(w2, i); + UINT32 s1 = w1; + UINT32 s2 = w2; + + UINT32 r1 = s1 * s2; + UINT32 r2 = (UINT16)ACCUM_L(i) + (r1 >> 16); + UINT32 r3 = (UINT16)ACCUM_M(i) + (r2 >> 16); + + SET_ACCUM_L((UINT16)r2, i); + SET_ACCUM_M((UINT16)r3, i); + SET_ACCUM_H(ACCUM_H(i) + (INT16)(r3 >> 16), i); + + m_vres[i] = SATURATE_ACCUM(i, 0, 0x0000, 0xffff); + } + WRITEBACK_RESULT(); +} + +static void cfunc_vmadl(void *param) +{ + ((rsp_cop2 *)param)->vmadl(); +} + + +// VMADM +// + +inline void rsp_cop2_drc::vmadm() +{ + int op = m_op; + + for (int i = 0; i < 8; i++) + { + UINT16 w1, w2; + GET_VS1(w1, i); + GET_VS2(w2, i); + UINT32 s1 = (INT32)(INT16)w1; + UINT32 s2 = (UINT16)w2; + + UINT32 r1 = s1 * s2; + UINT32 r2 = (UINT16)ACCUM_L(i) + (UINT16)(r1); + UINT32 r3 = (UINT16)ACCUM_M(i) + (r1 >> 16) + (r2 >> 16); + + SET_ACCUM_L((UINT16)r2, i); + SET_ACCUM_M((UINT16)r3, i); + SET_ACCUM_H((UINT16)ACCUM_H(i) + (UINT16)(r3 >> 16), i); + if ((INT32)(r1) < 0) + { + SET_ACCUM_H((UINT16)ACCUM_H(i) - 1, i); + } + + m_vres[i] = SATURATE_ACCUM(i, 1, 0x8000, 0x7fff); + } + WRITEBACK_RESULT(); +} + +static void cfunc_vmadm(void *param) +{ + ((rsp_cop2 *)param)->vmadm(); +} + + +// VMADN +// + +inline void rsp_cop2_drc::vmadn() +{ + int op = m_op; + + for (int i = 0; i < 8; i++) + { + UINT16 w1, w2; + GET_VS1(w1, i); + GET_VS2(w2, i); + INT32 s1 = (UINT16)w1; + INT32 s2 = (INT32)(INT16)w2; + + UINT64 q = (UINT64)ACCUM_LL(i); + q |= (((UINT64)ACCUM_L(i)) << 16); + q |= (((UINT64)ACCUM_M(i)) << 32); + q |= (((UINT64)ACCUM_H(i)) << 48); + q += (INT64)(s1*s2) << 16; + + SET_ACCUM_LL((UINT16)q, i); + SET_ACCUM_L((UINT16)(q >> 16), i); + SET_ACCUM_M((UINT16)(q >> 32), i); + SET_ACCUM_H((UINT16)(q >> 48), i); + + m_vres[i] = SATURATE_ACCUM(i, 0, 0x0000, 0xffff); + } + WRITEBACK_RESULT(); +} + +static void cfunc_vmadn(void *param) +{ + ((rsp_cop2 *)param)->vmadn(); +} + + +// 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 + +inline void rsp_cop2_drc::vmadh() +{ + int op = m_op; + + for (int i = 0; i < 8; i++) + { + INT16 w1, w2; + GET_VS1(w1, i); + GET_VS2(w2, i); + INT32 s1 = (INT32)(INT16)w1; + INT32 s2 = (INT32)(INT16)w2; + + INT32 accum = (UINT32)(UINT16)ACCUM_M(i); + accum |= ((UINT32)((UINT16)ACCUM_H(i))) << 16; + accum += s1 * s2; + + SET_ACCUM_H((UINT16)(accum >> 16), i); + SET_ACCUM_M((UINT16)accum, i); + + m_vres[i] = SATURATE_ACCUM(i, 1, 0x8000, 0x7fff); + } + WRITEBACK_RESULT(); +} + +static void cfunc_vmadh(void *param) +{ + ((rsp_cop2 *)param)->vmadh(); +} + + +// 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 + +inline void rsp_cop2_drc::vadd() +{ + int op = m_op; + + for (int i = 0; i < 8; i++) + { + INT16 w1, w2; + GET_VS1(w1, i); + GET_VS2(w2, i); + INT32 s1 = (INT32)(INT16)w1; + INT32 s2 = (INT32)(INT16)w2; + INT32 r = s1 + s2 + (((CARRY_FLAG(i)) != 0) ? 1 : 0); + + SET_ACCUM_L((INT16)(r), i); + + if (r > 32767) r = 32767; + if (r < -32768) r = -32768; + m_vres[i] = (INT16)(r); + } + CLEAR_ZERO_FLAGS(); + CLEAR_CARRY_FLAGS(); + WRITEBACK_RESULT(); +} + +static void cfunc_vadd(void *param) +{ + ((rsp_cop2 *)param)->vadd(); +} + + +// 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 + +inline void rsp_cop2_drc::vsub() +{ + int op = m_op; + + for (int i = 0; i < 8; i++) + { + INT16 w1, w2; + GET_VS1(w1, i); + GET_VS2(w2, i); + INT32 s1 = (INT32)(INT16)w1; + INT32 s2 = (INT32)(INT16)w2; + INT32 r = s1 - s2 - (((CARRY_FLAG(i)) != 0) ? 1 : 0); + + SET_ACCUM_L((INT16)(r), i); + + if (r > 32767) r = 32767; + if (r < -32768) r = -32768; + + m_vres[i] = (INT16)(r); + } + CLEAR_ZERO_FLAGS(); + CLEAR_CARRY_FLAGS(); + WRITEBACK_RESULT(); +} + +static void cfunc_vsub(void *param) +{ + ((rsp_cop2 *)param)->vsub(); +} + + +// 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 + +inline void rsp_cop2_drc::vabs() +{ + int op = m_op; + + for (int i = 0; i < 8; i++) + { + INT16 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(); +} + +static void cfunc_vabs(void *param) +{ + ((rsp_cop2 *)param)->vabs(); +} + + +// 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 + +inline void rsp_cop2_drc::vaddc() +{ + int op = m_op; + + CLEAR_ZERO_FLAGS(); + CLEAR_CARRY_FLAGS(); + + for (int i = 0; i < 8; i++) + { + INT16 w1, w2; + GET_VS1(w1, i); + GET_VS2(w2, i); + INT32 s1 = (UINT32)(UINT16)w1; + INT32 s2 = (UINT32)(UINT16)w2; + INT32 r = s1 + s2; + + m_vres[i] = (INT16)(r); + SET_ACCUM_L((INT16)r, i); + + if (r & 0xffff0000) + { + SET_CARRY_FLAG(i); + } + } + WRITEBACK_RESULT(); +} + +static void cfunc_vaddc(void *param) +{ + ((rsp_cop2 *)param)->vaddc(); +} + + +// 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 + +inline void rsp_cop2_drc::vsubc() +{ + int op = m_op; + + CLEAR_ZERO_FLAGS(); + CLEAR_CARRY_FLAGS(); + + for (int i = 0; i < 8; i++) + { + INT16 w1, w2; + GET_VS1(w1, i); + GET_VS2(w2, i); + INT32 s1 = (UINT32)(UINT16)w1; + INT32 s2 = (UINT32)(UINT16)w2; + INT32 r = s1 - s2; + + m_vres[i] = (INT16)(r); + SET_ACCUM_L((UINT16)r, i); + + if ((UINT16)(r) != 0) + { + SET_ZERO_FLAG(i); + } + if (r & 0xffff0000) + { + SET_CARRY_FLAG(i); + } + } + WRITEBACK_RESULT(); +} + +static void cfunc_vsubc(void *param) +{ + ((rsp_cop2 *)param)->vsubc(); +} + + +// VADDB +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 010110 | +// ------------------------------------------------------ +// +// Adds two vector registers bytewise with rounding + +inline void rsp_cop2_drc::vaddb() +{ + const int op = m_op; + const int round = (EL == 0) ? 0 : (1 << (EL - 1)); + + for (int i = 0; i < 8; i++) + { + UINT16 w1, w2; + GET_VS1(w1, i); + GET_VS2(w2, i); + + UINT8 hb1 = w1 >> 8; + UINT8 lb1 = w1 & 0xff; + UINT8 hb2 = w2 >> 8; + UINT8 lb2 = w2 & 0xff; + + UINT16 hs = hb1 + hb2 + round; + UINT16 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(); +} + +static void cfunc_vaddb(void *param) +{ + ((rsp_cop2 *)param)->vaddb(); +} + + +// 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 + +inline void rsp_cop2_drc::vsaw() +{ + int op = m_op; + + 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; + } + } + } +} + +static void cfunc_vsaw(void *param) +{ + ((rsp_cop2 *)param)->vsaw(); +} + + +// 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 + +inline void rsp_cop2_drc::vlt() +{ + int op = m_op; + + CLEAR_COMPARE_FLAGS(); + CLEAR_CLIP2_FLAGS(); + + for (int i = 0; i < 8; i++) + { + INT16 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(); +} + +static void cfunc_vlt(void *param) +{ + ((rsp_cop2 *)param)->vlt(); +} + + +// 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 + +inline void rsp_cop2_drc::veq() +{ + int op = m_op; + + CLEAR_COMPARE_FLAGS(); + CLEAR_CLIP2_FLAGS(); + + for (int i = 0; i < 8; i++) + { + INT16 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(); +} + +static void cfunc_veq(void *param) +{ + ((rsp_cop2 *)param)->veq(); +} + + +// 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 + +inline void rsp_cop2_drc::vne() +{ + int op = m_op; + + CLEAR_COMPARE_FLAGS(); + CLEAR_CLIP2_FLAGS(); + + for (int i = 0; i < 8; i++) + { + INT16 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(); +} + +static void cfunc_vne(void *param) +{ + ((rsp_cop2 *)param)->vne(); +} + + +// 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 + +inline void rsp_cop2_drc::vge() +{ + int op = m_op; + + CLEAR_COMPARE_FLAGS(); + CLEAR_CLIP2_FLAGS(); + + for (int i = 0; i < 8; i++) + { + INT16 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(); +} + +static void cfunc_vge(void *param) +{ + ((rsp_cop2 *)param)->vge(); +} + + +// VCL +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100100 | +// ------------------------------------------------------ +// +// Vector clip low + +inline void rsp_cop2_drc::vcl() +{ + int op = m_op; + + for (int i = 0; i < 8; i++) + { + INT16 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)s2, i); + } + else + { + SET_ACCUM_L(s1, i); + } + } + else + { + if (CLIP1_FLAG(i) != 0) + { + if (((UINT32)(UINT16)(s1) + (UINT32)(UINT16)(s2)) > 0x10000) + { + SET_ACCUM_L(s1, i); + CLEAR_COMPARE_FLAG(i); + } + else + { + SET_ACCUM_L(-((UINT16)s2), i); + SET_COMPARE_FLAG(i); + } + } + else + { + if (((UINT32)(UINT16)(s1) + (UINT32)(UINT16)(s2)) != 0) + { + SET_ACCUM_L(s1, i); + CLEAR_COMPARE_FLAG(i); + } + else + { + SET_ACCUM_L(-((UINT16)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)(UINT16)s1 - (INT32)(UINT16)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(); +} + +static void cfunc_vcl(void *param) +{ + ((rsp_cop2 *)param)->vcl(); +} + + +// VCH +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100101 | +// ------------------------------------------------------ +// +// Vector clip high + +inline void rsp_cop2_drc::vch() +{ + int op = m_op; + + CLEAR_CARRY_FLAGS(); + CLEAR_COMPARE_FLAGS(); + CLEAR_CLIP1_FLAGS(); + CLEAR_ZERO_FLAGS(); + CLEAR_CLIP2_FLAGS(); + + UINT32 vce = 0; + for (int i = 0; i < 8; i++) + { + INT16 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)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(); +} + +static void cfunc_vch(void *param) +{ + ((rsp_cop2 *)param)->vch(); +} + + +// VCR +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100110 | +// ------------------------------------------------------ +// +// Vector clip reverse + +inline void rsp_cop2_drc::vcr() +{ + int op = m_op; + + CLEAR_CARRY_FLAGS(); + CLEAR_COMPARE_FLAGS(); + CLEAR_CLIP1_FLAGS(); + CLEAR_ZERO_FLAGS(); + CLEAR_CLIP2_FLAGS(); + + for (int i = 0; i < 8; i++) + { + INT16 s1, s2; + GET_VS1(s1, i); + GET_VS2(s2, i); + + if ((INT16)(s1 ^ s2) < 0) + { + if (s2 < 0) + { + SET_CLIP2_FLAG(i); + } + if ((s1 + s2) <= 0) + { + SET_ACCUM_L(~((UINT16)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(); +} + +static void cfunc_vcr(void *param) +{ + ((rsp_cop2 *)param)->vcr(); +} + + +// VMRG +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100111 | +// ------------------------------------------------------ +// +// Merges two vectors according to compare flags + +inline void rsp_cop2_drc::vmrg() +{ + int op = m_op; + + for (int i = 0; i < 8; i++) + { + INT16 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(); +} + +static void cfunc_vmrg(void *param) +{ + ((rsp_cop2 *)param)->vmrg(); +} + + +// VAND +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101000 | +// ------------------------------------------------------ +// +// Bitwise AND of two vector registers + +inline void rsp_cop2_drc::vand() +{ + int op = m_op; + + for (int i = 0; i < 8; i++) + { + UINT16 s1, s2; + GET_VS1(s1, i); + GET_VS2(s2, i); + m_vres[i] = s1 & s2; + SET_ACCUM_L(m_vres[i], i); + } + WRITEBACK_RESULT(); +} + +static void cfunc_vand(void *param) +{ + ((rsp_cop2 *)param)->vand(); +} + + +// VNAND +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101001 | +// ------------------------------------------------------ +// +// Bitwise NOT AND of two vector registers + +inline void rsp_cop2_drc::vnand() +{ + int op = m_op; + + for (int i = 0; i < 8; i++) + { + UINT16 s1, s2; + GET_VS1(s1, i); + GET_VS2(s2, i); + m_vres[i] = ~((s1 & s2)); + SET_ACCUM_L(m_vres[i], i); + } + WRITEBACK_RESULT(); +} + +static void cfunc_vnand(void *param) +{ + ((rsp_cop2 *)param)->vnand(); +} + + +// VOR +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101010 | +// ------------------------------------------------------ +// +// Bitwise OR of two vector registers + +inline void rsp_cop2_drc::vor() +{ + int op = m_op; + + for (int i = 0; i < 8; i++) + { + UINT16 s1, s2; + GET_VS1(s1, i); + GET_VS2(s2, i); + m_vres[i] = s1 | s2; + SET_ACCUM_L(m_vres[i], i); + } + WRITEBACK_RESULT(); +} + +static void cfunc_vor(void *param) +{ + ((rsp_cop2 *)param)->vor(); +} + + +// VNOR +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101011 | +// ------------------------------------------------------ +// +// Bitwise NOT OR of two vector registers + +inline void rsp_cop2_drc::vnor() +{ + int op = m_op; + + for (int i = 0; i < 8; i++) + { + UINT16 s1, s2; + GET_VS1(s1, i); + GET_VS2(s2, i); + m_vres[i] = ~(s1 | s2); + SET_ACCUM_L(m_vres[i], i); + } + WRITEBACK_RESULT(); +} + +static void cfunc_vnor(void *param) +{ + ((rsp_cop2 *)param)->vnor(); +} + + +// VXOR +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101100 | +// ------------------------------------------------------ +// +// Bitwise XOR of two vector registers + +inline void rsp_cop2_drc::vxor() +{ + int op = m_op; + + for (int i = 0; i < 8; i++) + { + UINT16 s1, s2; + GET_VS1(s1, i); + GET_VS2(s2, i); + m_vres[i] = s1 ^ s2; + SET_ACCUM_L(m_vres[i], i); + } + WRITEBACK_RESULT(); +} + +static void cfunc_vxor(void *param) +{ + ((rsp_cop2 *)param)->vxor(); +} + + +// VNXOR +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101101 | +// ------------------------------------------------------ +// +// Bitwise NOT XOR of two vector registers + +inline void rsp_cop2_drc::vnxor() +{ + int op = m_op; + + for (int i = 0; i < 8; i++) + { + UINT16 s1, s2; + GET_VS1(s1, i); + GET_VS2(s2, i); + m_vres[i] = ~(s1 ^ s2); + SET_ACCUM_L(m_vres[i], i); + } + WRITEBACK_RESULT(); +} + +static void cfunc_vnxor(void *param) +{ + ((rsp_cop2 *)param)->vnxor(); +} + + +// VRCP +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110000 | +// ------------------------------------------------------ +// +// Calculates reciprocal + +inline void rsp_cop2_drc::vrcp() +{ + int op = m_op; + + INT32 shifter = 0; + INT32 rec = (INT16)(VREG_S(VS2REG, EL & 7)); + INT32 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 address = ((datainput << shifter) & 0x7fc00000) >> 22; + INT32 fetchval = rsp_divtable[address]; + INT32 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)rec; + for (int i = 0; i < 8; i++) + { + SET_ACCUM_L(VREG_S(VS2REG, VEC_EL_2(EL, i)), i); + } +} + +static void cfunc_vrcp(void *param) +{ + ((rsp_cop2 *)param)->vrcp(); +} + + +// VRCPL +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110001 | +// ------------------------------------------------------ +// +// Calculates reciprocal low part + +inline void rsp_cop2_drc::vrcpl() +{ + int op = m_op; + + INT32 shifter = 0; + INT32 rec = (INT16)VREG_S(VS2REG, EL & 7); + INT32 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 address = (datainput << shifter) >> 22; + INT32 fetchval = rsp_divtable[address & 0x1ff]; + INT32 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)rec; + + for (int i = 0; i < 8; i++) + { + SET_ACCUM_L(VREG_S(VS2REG, VEC_EL_2(EL, i)), i); + } +} + +static void cfunc_vrcpl(void *param) +{ + ((rsp_cop2 *)param)->vrcpl(); +} + + +// VRCPH +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110010 | +// ------------------------------------------------------ +// +// Calculates reciprocal high part + +inline void rsp_cop2_drc::vrcph() +{ + int op = m_op; + + 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)(m_reciprocal_res >> 16); +} + +static void cfunc_vrcph(void *param) +{ + ((rsp_cop2 *)param)->vrcph(); +} + + +// VMOV +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110011 | +// ------------------------------------------------------ +// +// Moves element from vector to destination vector + +inline void rsp_cop2_drc::vmov() +{ + int op = m_op; + + 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); + } +} + +static void cfunc_vmov(void *param) +{ + ((rsp_cop2 *)param)->vmov(); +} + + +// VRSQ +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110100 | +// ------------------------------------------------------ +// +// Calculates reciprocal square-root + +inline void rsp_cop2_drc::vrsq() +{ + int op = m_op; + + INT32 shifter = 0; + INT32 rec = (INT16)VREG_S(VS2REG, EL & 7); + INT32 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 address = ((datainput << shifter) & 0x7fc00000) >> 22; + address = ((address | 0x200) & 0x3fe) | (shifter & 1); + + INT32 fetchval = rsp_divtable[address]; + INT32 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)rec; + for (int i = 0; i < 8; i++) + { + SET_ACCUM_L(VREG_S(VS2REG, VEC_EL_2(EL, i)), i); + } +} + +static void cfunc_vrsq(void *param) +{ + ((rsp_cop2 *)param)->vrsq(); +} + + +// VRSQL +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110101 | +// ------------------------------------------------------ +// +// Calculates reciprocal square-root low part + +inline void rsp_cop2_drc::vrsql() +{ + int op = m_op; + + INT32 shifter = 0; + INT32 rec = (INT16)VREG_S(VS2REG, EL & 7); + INT32 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 address = ((datainput << shifter) & 0x7fc00000) >> 22; + address = ((address | 0x200) & 0x3fe) | (shifter & 1); + + INT32 fetchval = rsp_divtable[address]; + INT32 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)(rec & 0xffff); + for (int i = 0; i < 8; i++) + { + SET_ACCUM_L(VREG_S(VS2REG, VEC_EL_2(EL, i)), i); + } +} + +static void cfunc_vrsql(void *param) +{ + ((rsp_cop2 *)param)->vrsql(); +} + + +// VRSQH +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110110 | +// ------------------------------------------------------ +// +// Calculates reciprocal square-root high part + +inline void rsp_cop2_drc::vrsqh() +{ + int op = m_op; + + 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)(m_reciprocal_res >> 16); // store high part +} + +static void cfunc_vrsqh(void *param) +{ + ((rsp_cop2 *)param)->vrsqh(); +} + + +/*------------------------------------------------- + generate_vector_opcode - generate code for a + vector opcode +-------------------------------------------------*/ + +int rsp_cop2_drc::generate_vector_opcode(drcuml_block *block, rsp_device::compiler_state *compiler, const opcode_desc *desc) +{ + UINT32 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_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vmulf, this); + return TRUE; + + case 0x01: /* VMULU */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vmulu, this); + return TRUE; + + case 0x04: /* VMUDL */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vmudl, this); + return TRUE; + + case 0x05: /* VMUDM */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vmudm, this); + return TRUE; + + case 0x06: /* VMUDN */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vmudn, this); + return TRUE; + + case 0x07: /* VMUDH */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vmudh, this); + return TRUE; + + case 0x08: /* VMACF */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vmacf, this); + return TRUE; + + case 0x09: /* VMACU */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vmacu, this); + return TRUE; + + case 0x0c: /* VMADL */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vmadl, this); + return TRUE; + + case 0x0d: /* VMADM */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vmadm, this); + return TRUE; + + case 0x0e: /* VMADN */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vmadn, this); + return TRUE; + + case 0x0f: /* VMADH */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vmadh, this); + return TRUE; + + case 0x10: /* VADD */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vadd, this); + return TRUE; + + case 0x11: /* VSUB */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vsub, this); + return TRUE; + + case 0x13: /* VABS */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vabs, this); + return TRUE; + + case 0x14: /* VADDC */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vaddc, this); + return TRUE; + + case 0x15: /* VSUBC */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vsubc, this); + return TRUE; + + case 0x16: /* VADDB */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vaddb, this); + return TRUE; + + case 0x17: /* VSUBB (reserved, functionally identical to VADDB) */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vaddb, this); + return TRUE; + + case 0x18: /* VACCB (reserved, functionally identical to VADDB) */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vaddb, this); + return TRUE; + + case 0x19: /* VSUCB (reserved, functionally identical to VADDB) */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vaddb, this); + return TRUE; + + case 0x1d: /* VSAW */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vsaw, this); + return TRUE; + + case 0x20: /* VLT */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vlt, this); + return TRUE; + + case 0x21: /* VEQ */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_veq, this); + return TRUE; + + case 0x22: /* VNE */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vne, this); + return TRUE; + + case 0x23: /* VGE */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vge, this); + return TRUE; + + case 0x24: /* VCL */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vcl, this); + return TRUE; + + case 0x25: /* VCH */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vch, this); + return TRUE; + + case 0x26: /* VCR */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vcr, this); + return TRUE; + + case 0x27: /* VMRG */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vmrg, this); + return TRUE; + + case 0x28: /* VAND */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vand, this); + return TRUE; + + case 0x29: /* VNAND */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vnand, this); + return TRUE; + + case 0x2a: /* VOR */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vor, this); + return TRUE; + + case 0x2b: /* VNOR */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vnor, this); + return TRUE; + + case 0x2c: /* VXOR */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vxor, this); + return TRUE; + + case 0x2d: /* VNXOR */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vnxor, this); + return TRUE; + + case 0x30: /* VRCP */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vrcp, this); + return TRUE; + + case 0x31: /* VRCPL */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vrcpl, this); + return TRUE; + + case 0x32: /* VRCPH */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vrcph, this); + return TRUE; + + case 0x33: /* VMOV */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vmov, this); + return TRUE; + + case 0x34: /* VRSQ */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vrsq, this); + return TRUE; + + case 0x35: /* VRSQL */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vrsql, this); + return TRUE; + + case 0x36: /* VRSQH */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_vrsqh, this); + return TRUE; + + case 0x37: /* VNOP */ + case 0x3F: /* VNULL */ + return TRUE; + + default: + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, unimplemented_opcode, &m_rsp); + return FALSE; + } +} + + +/*************************************************************************** + Vector Flag Reading/Writing +***************************************************************************/ + +inline void rsp_cop2_drc::mfc2() +{ + UINT32 op = m_op; + int el = (op >> 7) & 0xf; + + UINT16 b1 = VREG_B(VS1REG, (el+0) & 0xf); + UINT16 b2 = VREG_B(VS1REG, (el+1) & 0xf); + if (RTREG) RTVAL = (INT32)(INT16)((b1 << 8) | (b2)); +} + +static void cfunc_mfc2(void *param) +{ + ((rsp_cop2 *)param)->mfc2(); +} + +inline void rsp_cop2_drc::cfc2() +{ + UINT32 op = m_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; + } + } +} + +static void cfunc_cfc2(void *param) +{ + ((rsp_cop2 *)param)->cfc2(); +} + + +inline void rsp_cop2_drc::mtc2() +{ + UINT32 op = m_op; + int el = (op >> 7) & 0xf; + VREG_B(VS1REG, (el+0) & 0xf) = (RTVAL >> 8) & 0xff; + VREG_B(VS1REG, (el+1) & 0xf) = (RTVAL >> 0) & 0xff; +} + +static void cfunc_mtc2(void *param) +{ + ((rsp_cop2 *)param)->mtc2(); +} + + +inline void rsp_cop2_drc::ctc2() +{ + UINT32 op = m_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; + } +} + +static void cfunc_ctc2(void *param) +{ + ((rsp_cop2 *)param)->ctc2(); +} + +/*************************************************************************** + COP2 Opcode Compilation +***************************************************************************/ + +int rsp_cop2_drc::generate_cop2(drcuml_block *block, rsp_device::compiler_state *compiler, const opcode_desc *desc) +{ + UINT32 op = desc->opptr.l[0]; + UINT8 opswitch = RSREG; + + switch (opswitch) + { + case 0x00: /* MFCz */ + if (RTREG != 0) + { + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_mfc2, this); // callc mfc2 + } + return TRUE; + + case 0x02: /* CFCz */ + if (RTREG != 0) + { + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_cfc2, this); // callc cfc2 + } + return TRUE; + + case 0x04: /* MTCz */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_mtc2, this); // callc mtc2 + return TRUE; + + case 0x06: /* CTCz */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, 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; +}
\ No newline at end of file diff --git a/src/emu/cpu/rsp/rspcp2d.h b/src/emu/cpu/rsp/rspcp2d.h new file mode 100644 index 00000000000..51c00dc53f3 --- /dev/null +++ b/src/emu/cpu/rsp/rspcp2d.h @@ -0,0 +1,110 @@ +/*************************************************************************** + + rspcp2d.h + + Interface file for Reality Signal Processor (RSP) vector extensions + using Universal Machine Language (UML) dynamic recompilation. + + Copyright the MESS team + Released for general non-commercial use under the MAME license + Visit http://mamedev.org for licensing and usage restrictions. + +***************************************************************************/ + +#pragma once + +#ifndef __RSPCP2D_H__ +#define __RSPCP2D_H__ + +#include "cpu/drcuml.h" +#include "rsp.h" +#include "rspcp2.h" + +class rsp_cop2_drc : public rsp_cop2 +{ + friend class rsp_device; + + rsp_cop2_drc(rsp_device &rsp, running_machine &machine) : rsp_cop2(rsp, machine) { } + + virtual int generate_cop2(drcuml_block *block, rsp_device::compiler_state *compiler, const opcode_desc *desc); + virtual int generate_lwc2(drcuml_block *block, rsp_device::compiler_state *compiler, const opcode_desc *desc); + virtual int generate_swc2(drcuml_block *block, rsp_device::compiler_state *compiler, const opcode_desc *desc); + + virtual void state_string_export(const int index, astring &string); + + void cfunc_unimplemented_opcode(); +public: + 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(); + +private: + virtual int generate_vector_opcode(drcuml_block *block, rsp_device::compiler_state *compiler, const opcode_desc *desc); +}; + +#endif /* __RSPCP2D_H__ */
\ No newline at end of file diff --git a/src/emu/cpu/rsp/rspcp2s.c b/src/emu/cpu/rsp/rspcp2s.c new file mode 100644 index 00000000000..5f53bb927c6 --- /dev/null +++ b/src/emu/cpu/rsp/rspcp2s.c @@ -0,0 +1,3633 @@ +/*************************************************************************** + + rspcp2s.c + + Universal machine language-based Nintendo/SGI RSP COP2 emulator, with + SSSE3 SIMD optimizations. + Written by Harmony of the MESS team. + + Copyright the MESS team. + Released for general non-commercial use under the MAME license + Visit http://mamedev.org for licensing and usage restrictions. + +***************************************************************************/ + +#include "emu.h" +#include "rsp.h" +#include "rspdiv.h" +#include "rspcp2.h" +#include "cpu/drcfe.h" +#include "cpu/drcuml.h" +#include "cpu/drcumlsh.h" + +using namespace uml; + +/*************************************************************************** + 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 EXTRACT16(reg, value, element) \ + switch((element) & 7) \ + { \ + case 0: value = _mm_extract_epi16(reg, 0); break; \ + case 1: value = _mm_extract_epi16(reg, 1); break; \ + case 2: value = _mm_extract_epi16(reg, 2); break; \ + case 3: value = _mm_extract_epi16(reg, 3); break; \ + case 4: value = _mm_extract_epi16(reg, 4); break; \ + case 5: value = _mm_extract_epi16(reg, 5); break; \ + case 6: value = _mm_extract_epi16(reg, 6); break; \ + case 7: value = _mm_extract_epi16(reg, 7); break; \ + } + + +#define INSERT16(reg, value, element) \ + switch((element) & 7) \ + { \ + case 0: reg = _mm_insert_epi16(reg, value, 0); break; \ + case 1: reg = _mm_insert_epi16(reg, value, 1); break; \ + case 2: reg = _mm_insert_epi16(reg, value, 2); break; \ + case 3: reg = _mm_insert_epi16(reg, value, 3); break; \ + case 4: reg = _mm_insert_epi16(reg, value, 4); break; \ + case 5: reg = _mm_insert_epi16(reg, value, 5); break; \ + case 6: reg = _mm_insert_epi16(reg, value, 6); break; \ + case 7: reg = _mm_insert_epi16(reg, value, 7); break; \ + } + + +#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)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 + +static void cfunc_mfc2(void *param); +static void cfunc_cfc2(void *param); +static void cfunc_mtc2(void *param); +static void cfunc_ctc2(void *param); + +inline UINT16 rsp_cop2_simd::ACCUM_H(int x) +{ + UINT16 out; + EXTRACT16(m_accum_h, out, x); + return out; +} + +inline UINT16 rsp_cop2_simd::ACCUM_M(int x) +{ + UINT16 out; + EXTRACT16(m_accum_m, out, x); + return out; +} + +inline UINT16 rsp_cop2_simd::ACCUM_L(int x) +{ + UINT16 out; + EXTRACT16(m_accum_l, out, x); + return out; +} + +inline UINT16 rsp_cop2_simd::ACCUM_LL(int x) +{ + UINT16 out; + EXTRACT16(m_accum_ll, out, x); + return out; +} + +#define SET_ACCUM_H(v, x) INSERT16(m_accum_h, v, x); +#define SET_ACCUM_M(v, x) INSERT16(m_>accum_m, v, x); +#define SET_ACCUM_L(v, x) INSERT16(m_accum_l, v, x); +#define SET_ACCUM_LL(v, x) INSERT16(m_accum_ll, v, x); + +#define GET_VS1(out, i) EXTRACT16(m_xv[VS1REG], out, i); +#define GET_VS2(out, i) EXTRACT16(m_xv[VS2REG], out, VEC_EL_2(EL, i)); + +inline UINT16 rsp_cop2_simd::CARRY_FLAG(const int x) +{ + UINT16 out; + EXTRACT16(m_xvflag[CARRY], out, x); + return out; +} + +inline UINT16 rsp_cop2_simd::COMPARE_FLAG(const int x) +{ + UINT16 out; + EXTRACT16(m_xvflag[COMPARE], out, x); + return out; +} + +inline UINT16 rsp_cop2_simd::CLIP1_FLAG(const int x) +{ + UINT16 out; + EXTRACT16(m_xvflag[CLIP1], out, x); + return out; +} + +inline UINT16 rsp_cop2_simd::ZERO_FLAG(const int x) +{ + UINT16 out; + EXTRACT16(m_xvflag[ZERO], out, x); + return out; +} + +inline UINT16 rsp_cop2_simd::CLIP2_FLAG(const int x) +{ + UINT16 out; + EXTRACT16(m_xvflag[CLIP2], out, x); + return out; +} + +#define CLEAR_CARRY_FLAGS() { m_xvflag[CARRY] = _mm_setzero_si128(); } +#define CLEAR_COMPARE_FLAGS() { m_xvflag[COMPARE] = _mm_setzero_si128(); } +#define CLEAR_CLIP1_FLAGS() { m_xvflag[CLIP1] = _mm_setzero_si128(); } +#define CLEAR_ZERO_FLAGS() { m_xvflag[ZERO] = _mm_setzero_si128(); } +#define CLEAR_CLIP2_FLAGS() { m_xvflag[CLIP2] = _mm_setzero_si128(); } + +#define SET_CARRY_FLAG(x) { INSERT16(m_xvflag[CARRY], 0xffff, x); } +#define SET_COMPARE_FLAG(x) { INSERT16(m_xvflag[COMPARE], 0xffff, x); } +#define SET_CLIP1_FLAG(x) { INSERT16(m_xvflag[CLIP1], 0xffff, x); } +#define SET_ZERO_FLAG(x) { INSERT16(m_xvflag[ZERO], 0xffff, x); } +#define SET_CLIP2_FLAG(x) { INSERT16(m_xvflag[CLIP2], 0xffff, x); } + +#define CLEAR_CARRY_FLAG(x) { INSERT16(m_xvflag[CARRY], 0, x); } +#define CLEAR_COMPARE_FLAG(x) { INSERT16(m_xvflag[COMPARE], 0, x); } +#define CLEAR_CLIP1_FLAG(x) { INSERT16(m_xvflag[CLIP1], 0, x); } +#define CLEAR_ZERO_FLAG(x) { INSERT16(m_xvflag[ZERO], 0, x); } +#define CLEAR_CLIP2_FLAG(x) { INSERT16(m_xvflag[CLIP2], 0, x); } + +#define WRITEBACK_RESULT() { \ + INSERT16(m_xv[VDREG], m_vres[0], 0); \ + INSERT16(m_xv[VDREG], m_vres[1], 1); \ + INSERT16(m_xv[VDREG], m_vres[2], 2); \ + INSERT16(m_xv[VDREG], m_vres[3], 3); \ + INSERT16(m_xv[VDREG], m_vres[4], 4); \ + INSERT16(m_xv[VDREG], m_vres[5], 5); \ + INSERT16(m_xv[VDREG], m_vres[6], 6); \ + INSERT16(m_xv[VDREG], m_vres[7], 7); \ +} +#endif + +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 +}; + +static __m128i vec_himask; +static __m128i vec_lomask; +static __m128i vec_hibit; +static __m128i vec_lobit; +static __m128i vec_n32768; +static __m128i vec_32767; +static __m128i vec_flagmask; +static __m128i vec_shiftmask2; +static __m128i vec_shiftmask4; +static __m128i vec_flag_reverse; +static __m128i vec_neg1; +static __m128i vec_zero; +static __m128i vec_shuf[16]; +static __m128i vec_shuf_inverse[16]; + +rsp_cop2_simd::rsp_cop2_simd(rsp_device &rsp, running_machine &machine) : rsp_cop2(rsp, machine) + : m_accum_h(0) + , m_accum_m(0) + , m_accum_l(0) + , m_accum_ll(0) +#if SIMUL_SIMD + , m_old_reciprocal_res(0) + , m_old_reciprocal_high(0) + , m_old_dp_allowed(0) + , m_scalar_reciprocal_res(0) + , m_scalar_reciprocal_high(0) + , m_scalar_dp_allowed(0) + , m_simd_reciprocal_res(0) + , m_simd_reciprocal_high(0) + , m_simd_dp_allowed(0) +#endif +{ +#if SIMUL_SIMD + memset(m_old_r, 0, sizeof(m_old_r)); + memset(m_old_dmem, 0, sizeof(m_old_dmem)); + memset(m_scalar_r, 0, sizeof(m_scalar_r)); + memset(m_scalar_dmem, 0, sizeof(m_scalar_dmem)); +#endif + memset(m_xv, 0, sizeof(m_xv)); + memset(m_xvflag, 0, sizeof(m_xvflag)); + + vec_shuf_inverse[ 0] = _mm_set_epi16(0x0f0e, 0x0d0c, 0x0b0a, 0x0908, 0x0706, 0x0504, 0x0302, 0x0100); // none + vec_shuf_inverse[ 1] = _mm_set_epi16(0x0f0e, 0x0d0c, 0x0b0a, 0x0908, 0x0706, 0x0504, 0x0302, 0x0100); // ??? + vec_shuf_inverse[ 2] = _mm_set_epi16(0x0d0c, 0x0d0c, 0x0908, 0x0908, 0x0504, 0x0504, 0x0100, 0x0100); // 0q + vec_shuf_inverse[ 3] = _mm_set_epi16(0x0f0e, 0x0f0e, 0x0b0a, 0x0b0a, 0x0706, 0x0706, 0x0302, 0x0302); // 1q + vec_shuf_inverse[ 4] = _mm_set_epi16(0x0908, 0x0908, 0x0908, 0x0908, 0x0100, 0x0100, 0x0100, 0x0100); // 0h + vec_shuf_inverse[ 5] = _mm_set_epi16(0x0b0a, 0x0b0a, 0x0b0a, 0x0b0a, 0x0302, 0x0302, 0x0302, 0x0302); // 1h + vec_shuf_inverse[ 6] = _mm_set_epi16(0x0d0c, 0x0d0c, 0x0d0c, 0x0d0c, 0x0504, 0x0504, 0x0504, 0x0504); // 2h + vec_shuf_inverse[ 7] = _mm_set_epi16(0x0f0e, 0x0f0e, 0x0f0e, 0x0f0e, 0x0706, 0x0706, 0x0706, 0x0706); // 3h + vec_shuf_inverse[ 8] = _mm_set_epi16(0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100); // 0 + vec_shuf_inverse[ 9] = _mm_set_epi16(0x0302, 0x0302, 0x0302, 0x0302, 0x0302, 0x0302, 0x0302, 0x0302); // 1 + vec_shuf_inverse[10] = _mm_set_epi16(0x0504, 0x0504, 0x0504, 0x0504, 0x0504, 0x0504, 0x0504, 0x0504); // 2 + vec_shuf_inverse[11] = _mm_set_epi16(0x0706, 0x0706, 0x0706, 0x0706, 0x0706, 0x0706, 0x0706, 0x0706); // 3 + vec_shuf_inverse[12] = _mm_set_epi16(0x0908, 0x0908, 0x0908, 0x0908, 0x0908, 0x0908, 0x0908, 0x0908); // 4 + vec_shuf_inverse[13] = _mm_set_epi16(0x0b0a, 0x0b0a, 0x0b0a, 0x0b0a, 0x0b0a, 0x0b0a, 0x0b0a, 0x0b0a); // 5 + vec_shuf_inverse[14] = _mm_set_epi16(0x0d0c, 0x0d0c, 0x0d0c, 0x0d0c, 0x0d0c, 0x0d0c, 0x0d0c, 0x0d0c); // 6 + vec_shuf_inverse[15] = _mm_set_epi16(0x0f0e, 0x0f0e, 0x0f0e, 0x0f0e, 0x0f0e, 0x0f0e, 0x0f0e, 0x0f0e); // 7 + + vec_shuf[ 0] = _mm_set_epi16(0x0100, 0x0302, 0x0504, 0x0706, 0x0908, 0x0b0a, 0x0d0c, 0x0f0e); // none + vec_shuf[ 1] = _mm_set_epi16(0x0100, 0x0302, 0x0504, 0x0706, 0x0908, 0x0b0a, 0x0d0c, 0x0f0e); // ??? + vec_shuf[ 2] = _mm_set_epi16(0x0302, 0x0302, 0x0706, 0x0706, 0x0b0a, 0x0b0a, 0x0f0e, 0x0f0e); // 0q + vec_shuf[ 3] = _mm_set_epi16(0x0100, 0x0100, 0x0504, 0x0706, 0x0908, 0x0908, 0x0d0c, 0x0d0c); // 1q + vec_shuf[ 4] = _mm_set_epi16(0x0706, 0x0706, 0x0706, 0x0706, 0x0f0e, 0x0f0e, 0x0f0e, 0x0f0e); // 0q + vec_shuf[ 5] = _mm_set_epi16(0x0504, 0x0504, 0x0504, 0x0504, 0x0d0c, 0x0d0c, 0x0d0c, 0x0d0c); // 1q + vec_shuf[ 6] = _mm_set_epi16(0x0302, 0x0302, 0x0302, 0x0302, 0x0b0a, 0x0b0a, 0x0b0a, 0x0b0a); // 2q + vec_shuf[ 7] = _mm_set_epi16(0x0100, 0x0100, 0x0100, 0x0100, 0x0908, 0x0908, 0x0908, 0x0908); // 3q + vec_shuf[ 8] = _mm_set_epi16(0x0f0e, 0x0f0e, 0x0f0e, 0x0f0e, 0x0f0e, 0x0f0e, 0x0f0e, 0x0f0e); // 0 + vec_shuf[ 9] = _mm_set_epi16(0x0d0c, 0x0d0c, 0x0d0c, 0x0d0c, 0x0d0c, 0x0d0c, 0x0d0c, 0x0d0c); // 1 + vec_shuf[10] = _mm_set_epi16(0x0b0a, 0x0b0a, 0x0b0a, 0x0b0a, 0x0b0a, 0x0b0a, 0x0b0a, 0x0b0a); // 2 + vec_shuf[11] = _mm_set_epi16(0x0908, 0x0908, 0x0908, 0x0908, 0x0908, 0x0908, 0x0908, 0x0908); // 3 + vec_shuf[12] = _mm_set_epi16(0x0706, 0x0706, 0x0706, 0x0706, 0x0706, 0x0706, 0x0706, 0x0706); // 4 + vec_shuf[13] = _mm_set_epi16(0x0504, 0x0504, 0x0504, 0x0504, 0x0504, 0x0504, 0x0504, 0x0504); // 5 + vec_shuf[14] = _mm_set_epi16(0x0302, 0x0302, 0x0302, 0x0302, 0x0302, 0x0302, 0x0302, 0x0302); // 6 + vec_shuf[15] = _mm_set_epi16(0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100); // 7 + m_accum_h = _mm_setzero_si128(); + m_accum_m = _mm_setzero_si128(); + m_accum_l = _mm_setzero_si128(); + m_accum_ll = _mm_setzero_si128(); + vec_neg1 = _mm_set_epi64x(0xffffffffffffffffL, 0xffffffffffffffffL); + vec_zero = _mm_setzero_si128(); + vec_himask = _mm_set_epi64x(0xffff0000ffff0000L, 0xffff0000ffff0000L); + vec_lomask = _mm_set_epi64x(0x0000ffff0000ffffL, 0x0000ffff0000ffffL); + vec_hibit = _mm_set_epi64x(0x0001000000010000L, 0x0001000000010000L); + vec_lobit = _mm_set_epi64x(0x0000000100000001L, 0x0000000100000001L); + vec_32767 = _mm_set_epi64x(0x7fff7fff7fff7fffL, 0x7fff7fff7fff7fffL); + vec_n32768 = _mm_set_epi64x(0x8000800080008000L, 0x8000800080008000L); + vec_flagmask = _mm_set_epi64x(0x0001000100010001L, 0x0001000100010001L); + vec_shiftmask2 = _mm_set_epi64x(0x0000000300000003L, 0x0000000300000003L); + vec_shiftmask4 = _mm_set_epi64x(0x000000000000000fL, 0x000000000000000fL); + vec_flag_reverse = _mm_set_epi16(0x0100, 0x0302, 0x0504, 0x0706, 0x0908, 0x0b0a, 0x0d0c, 0x0f0e); +} + +void rsp_cop2_simd::state_string_export(const int index, astring &string) +{ + switch (index) + { + case RSP_V0: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[ 0], 7), (UINT16)_mm_extract_epi16(m_xv[ 0], 6), (UINT16)_mm_extract_epi16(m_xv[ 0], 5), (UINT16)_mm_extract_epi16(m_xv[ 0], 4), (UINT16)_mm_extract_epi16(m_xv[ 0], 3), (UINT16)_mm_extract_epi16(m_xv[ 0], 2), (UINT16)_mm_extract_epi16(m_xv[ 0], 1), (UINT16)_mm_extract_epi16(m_xv[ 0], 0)); + break; + case RSP_V1: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[ 1], 7), (UINT16)_mm_extract_epi16(m_xv[ 1], 6), (UINT16)_mm_extract_epi16(m_xv[ 1], 5), (UINT16)_mm_extract_epi16(m_xv[ 1], 4), (UINT16)_mm_extract_epi16(m_xv[ 1], 3), (UINT16)_mm_extract_epi16(m_xv[ 1], 2), (UINT16)_mm_extract_epi16(m_xv[ 1], 1), (UINT16)_mm_extract_epi16(m_xv[ 1], 0)); + break; + case RSP_V2: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[ 2], 7), (UINT16)_mm_extract_epi16(m_xv[ 2], 6), (UINT16)_mm_extract_epi16(m_xv[ 2], 5), (UINT16)_mm_extract_epi16(m_xv[ 2], 4), (UINT16)_mm_extract_epi16(m_xv[ 2], 3), (UINT16)_mm_extract_epi16(m_xv[ 2], 2), (UINT16)_mm_extract_epi16(m_xv[ 2], 1), (UINT16)_mm_extract_epi16(m_xv[ 2], 0)); + break; + case RSP_V3: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[ 3], 7), (UINT16)_mm_extract_epi16(m_xv[ 3], 6), (UINT16)_mm_extract_epi16(m_xv[ 3], 5), (UINT16)_mm_extract_epi16(m_xv[ 3], 4), (UINT16)_mm_extract_epi16(m_xv[ 3], 3), (UINT16)_mm_extract_epi16(m_xv[ 3], 2), (UINT16)_mm_extract_epi16(m_xv[ 3], 1), (UINT16)_mm_extract_epi16(m_xv[ 3], 0)); + break; + case RSP_V4: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[ 4], 7), (UINT16)_mm_extract_epi16(m_xv[ 4], 6), (UINT16)_mm_extract_epi16(m_xv[ 4], 5), (UINT16)_mm_extract_epi16(m_xv[ 4], 4), (UINT16)_mm_extract_epi16(m_xv[ 4], 3), (UINT16)_mm_extract_epi16(m_xv[ 4], 2), (UINT16)_mm_extract_epi16(m_xv[ 4], 1), (UINT16)_mm_extract_epi16(m_xv[ 4], 0)); + break; + case RSP_V5: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[ 5], 7), (UINT16)_mm_extract_epi16(m_xv[ 5], 6), (UINT16)_mm_extract_epi16(m_xv[ 5], 5), (UINT16)_mm_extract_epi16(m_xv[ 5], 4), (UINT16)_mm_extract_epi16(m_xv[ 5], 3), (UINT16)_mm_extract_epi16(m_xv[ 5], 2), (UINT16)_mm_extract_epi16(m_xv[ 5], 1), (UINT16)_mm_extract_epi16(m_xv[ 5], 0)); + break; + case RSP_V6: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[ 6], 7), (UINT16)_mm_extract_epi16(m_xv[ 6], 6), (UINT16)_mm_extract_epi16(m_xv[ 6], 5), (UINT16)_mm_extract_epi16(m_xv[ 6], 4), (UINT16)_mm_extract_epi16(m_xv[ 6], 3), (UINT16)_mm_extract_epi16(m_xv[ 6], 2), (UINT16)_mm_extract_epi16(m_xv[ 6], 1), (UINT16)_mm_extract_epi16(m_xv[ 6], 0)); + break; + case RSP_V7: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[ 7], 7), (UINT16)_mm_extract_epi16(m_xv[ 7], 6), (UINT16)_mm_extract_epi16(m_xv[ 7], 5), (UINT16)_mm_extract_epi16(m_xv[ 7], 4), (UINT16)_mm_extract_epi16(m_xv[ 7], 3), (UINT16)_mm_extract_epi16(m_xv[ 7], 2), (UINT16)_mm_extract_epi16(m_xv[ 7], 1), (UINT16)_mm_extract_epi16(m_xv[ 7], 0)); + break; + case RSP_V8: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[ 8], 7), (UINT16)_mm_extract_epi16(m_xv[ 8], 6), (UINT16)_mm_extract_epi16(m_xv[ 8], 5), (UINT16)_mm_extract_epi16(m_xv[ 8], 4), (UINT16)_mm_extract_epi16(m_xv[ 8], 3), (UINT16)_mm_extract_epi16(m_xv[ 8], 2), (UINT16)_mm_extract_epi16(m_xv[ 8], 1), (UINT16)_mm_extract_epi16(m_xv[ 8], 0)); + break; + case RSP_V9: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[ 9], 7), (UINT16)_mm_extract_epi16(m_xv[ 9], 6), (UINT16)_mm_extract_epi16(m_xv[ 9], 5), (UINT16)_mm_extract_epi16(m_xv[ 9], 4), (UINT16)_mm_extract_epi16(m_xv[ 9], 3), (UINT16)_mm_extract_epi16(m_xv[ 9], 2), (UINT16)_mm_extract_epi16(m_xv[ 9], 1), (UINT16)_mm_extract_epi16(m_xv[ 9], 0)); + break; + case RSP_V10: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[10], 7), (UINT16)_mm_extract_epi16(m_xv[10], 6), (UINT16)_mm_extract_epi16(m_xv[10], 5), (UINT16)_mm_extract_epi16(m_xv[10], 4), (UINT16)_mm_extract_epi16(m_xv[10], 3), (UINT16)_mm_extract_epi16(m_xv[10], 2), (UINT16)_mm_extract_epi16(m_xv[10], 1), (UINT16)_mm_extract_epi16(m_xv[10], 0)); + break; + case RSP_V11: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[11], 7), (UINT16)_mm_extract_epi16(m_xv[11], 6), (UINT16)_mm_extract_epi16(m_xv[11], 5), (UINT16)_mm_extract_epi16(m_xv[11], 4), (UINT16)_mm_extract_epi16(m_xv[11], 3), (UINT16)_mm_extract_epi16(m_xv[11], 2), (UINT16)_mm_extract_epi16(m_xv[11], 1), (UINT16)_mm_extract_epi16(m_xv[11], 0)); + break; + case RSP_V12: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[12], 7), (UINT16)_mm_extract_epi16(m_xv[12], 6), (UINT16)_mm_extract_epi16(m_xv[12], 5), (UINT16)_mm_extract_epi16(m_xv[12], 4), (UINT16)_mm_extract_epi16(m_xv[12], 3), (UINT16)_mm_extract_epi16(m_xv[12], 2), (UINT16)_mm_extract_epi16(m_xv[12], 1), (UINT16)_mm_extract_epi16(m_xv[12], 0)); + break; + case RSP_V13: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[13], 7), (UINT16)_mm_extract_epi16(m_xv[13], 6), (UINT16)_mm_extract_epi16(m_xv[13], 5), (UINT16)_mm_extract_epi16(m_xv[13], 4), (UINT16)_mm_extract_epi16(m_xv[13], 3), (UINT16)_mm_extract_epi16(m_xv[13], 2), (UINT16)_mm_extract_epi16(m_xv[13], 1), (UINT16)_mm_extract_epi16(m_xv[13], 0)); + break; + case RSP_V14: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[14], 7), (UINT16)_mm_extract_epi16(m_xv[14], 6), (UINT16)_mm_extract_epi16(m_xv[14], 5), (UINT16)_mm_extract_epi16(m_xv[14], 4), (UINT16)_mm_extract_epi16(m_xv[14], 3), (UINT16)_mm_extract_epi16(m_xv[14], 2), (UINT16)_mm_extract_epi16(m_xv[14], 1), (UINT16)_mm_extract_epi16(m_xv[14], 0)); + break; + case RSP_V15: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[15], 7), (UINT16)_mm_extract_epi16(m_xv[15], 6), (UINT16)_mm_extract_epi16(m_xv[15], 5), (UINT16)_mm_extract_epi16(m_xv[15], 4), (UINT16)_mm_extract_epi16(m_xv[15], 3), (UINT16)_mm_extract_epi16(m_xv[15], 2), (UINT16)_mm_extract_epi16(m_xv[15], 1), (UINT16)_mm_extract_epi16(m_xv[15], 0)); + break; + case RSP_V16: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[16], 7), (UINT16)_mm_extract_epi16(m_xv[16], 6), (UINT16)_mm_extract_epi16(m_xv[16], 5), (UINT16)_mm_extract_epi16(m_xv[16], 4), (UINT16)_mm_extract_epi16(m_xv[16], 3), (UINT16)_mm_extract_epi16(m_xv[16], 2), (UINT16)_mm_extract_epi16(m_xv[16], 1), (UINT16)_mm_extract_epi16(m_xv[16], 0)); + break; + case RSP_V17: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[17], 7), (UINT16)_mm_extract_epi16(m_xv[17], 6), (UINT16)_mm_extract_epi16(m_xv[17], 5), (UINT16)_mm_extract_epi16(m_xv[17], 4), (UINT16)_mm_extract_epi16(m_xv[17], 3), (UINT16)_mm_extract_epi16(m_xv[17], 2), (UINT16)_mm_extract_epi16(m_xv[17], 1), (UINT16)_mm_extract_epi16(m_xv[17], 0)); + break; + case RSP_V18: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[18], 7), (UINT16)_mm_extract_epi16(m_xv[18], 6), (UINT16)_mm_extract_epi16(m_xv[18], 5), (UINT16)_mm_extract_epi16(m_xv[18], 4), (UINT16)_mm_extract_epi16(m_xv[18], 3), (UINT16)_mm_extract_epi16(m_xv[18], 2), (UINT16)_mm_extract_epi16(m_xv[18], 1), (UINT16)_mm_extract_epi16(m_xv[18], 0)); + break; + case RSP_V19: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[19], 7), (UINT16)_mm_extract_epi16(m_xv[19], 6), (UINT16)_mm_extract_epi16(m_xv[19], 5), (UINT16)_mm_extract_epi16(m_xv[19], 4), (UINT16)_mm_extract_epi16(m_xv[19], 3), (UINT16)_mm_extract_epi16(m_xv[19], 2), (UINT16)_mm_extract_epi16(m_xv[19], 1), (UINT16)_mm_extract_epi16(m_xv[19], 0)); + break; + case RSP_V20: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[20], 7), (UINT16)_mm_extract_epi16(m_xv[20], 6), (UINT16)_mm_extract_epi16(m_xv[20], 5), (UINT16)_mm_extract_epi16(m_xv[20], 4), (UINT16)_mm_extract_epi16(m_xv[20], 3), (UINT16)_mm_extract_epi16(m_xv[20], 2), (UINT16)_mm_extract_epi16(m_xv[20], 1), (UINT16)_mm_extract_epi16(m_xv[20], 0)); + break; + case RSP_V21: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[21], 7), (UINT16)_mm_extract_epi16(m_xv[21], 6), (UINT16)_mm_extract_epi16(m_xv[21], 5), (UINT16)_mm_extract_epi16(m_xv[21], 4), (UINT16)_mm_extract_epi16(m_xv[21], 3), (UINT16)_mm_extract_epi16(m_xv[21], 2), (UINT16)_mm_extract_epi16(m_xv[21], 1), (UINT16)_mm_extract_epi16(m_xv[21], 0)); + break; + case RSP_V22: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[22], 7), (UINT16)_mm_extract_epi16(m_xv[22], 6), (UINT16)_mm_extract_epi16(m_xv[22], 5), (UINT16)_mm_extract_epi16(m_xv[22], 4), (UINT16)_mm_extract_epi16(m_xv[22], 3), (UINT16)_mm_extract_epi16(m_xv[22], 2), (UINT16)_mm_extract_epi16(m_xv[22], 1), (UINT16)_mm_extract_epi16(m_xv[22], 0)); + break; + case RSP_V23: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[23], 7), (UINT16)_mm_extract_epi16(m_xv[23], 6), (UINT16)_mm_extract_epi16(m_xv[23], 5), (UINT16)_mm_extract_epi16(m_xv[23], 4), (UINT16)_mm_extract_epi16(m_xv[23], 3), (UINT16)_mm_extract_epi16(m_xv[23], 2), (UINT16)_mm_extract_epi16(m_xv[23], 1), (UINT16)_mm_extract_epi16(m_xv[23], 0)); + break; + case RSP_V24: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[24], 7), (UINT16)_mm_extract_epi16(m_xv[24], 6), (UINT16)_mm_extract_epi16(m_xv[24], 5), (UINT16)_mm_extract_epi16(m_xv[24], 4), (UINT16)_mm_extract_epi16(m_xv[24], 3), (UINT16)_mm_extract_epi16(m_xv[24], 2), (UINT16)_mm_extract_epi16(m_xv[24], 1), (UINT16)_mm_extract_epi16(m_xv[24], 0)); + break; + case RSP_V25: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[25], 7), (UINT16)_mm_extract_epi16(m_xv[25], 6), (UINT16)_mm_extract_epi16(m_xv[25], 5), (UINT16)_mm_extract_epi16(m_xv[25], 4), (UINT16)_mm_extract_epi16(m_xv[25], 3), (UINT16)_mm_extract_epi16(m_xv[25], 2), (UINT16)_mm_extract_epi16(m_xv[25], 1), (UINT16)_mm_extract_epi16(m_xv[25], 0)); + break; + case RSP_V26: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[26], 7), (UINT16)_mm_extract_epi16(m_xv[26], 6), (UINT16)_mm_extract_epi16(m_xv[26], 5), (UINT16)_mm_extract_epi16(m_xv[26], 4), (UINT16)_mm_extract_epi16(m_xv[26], 3), (UINT16)_mm_extract_epi16(m_xv[26], 2), (UINT16)_mm_extract_epi16(m_xv[26], 1), (UINT16)_mm_extract_epi16(m_xv[26], 0)); + break; + case RSP_V27: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[27], 7), (UINT16)_mm_extract_epi16(m_xv[27], 6), (UINT16)_mm_extract_epi16(m_xv[27], 5), (UINT16)_mm_extract_epi16(m_xv[27], 4), (UINT16)_mm_extract_epi16(m_xv[27], 3), (UINT16)_mm_extract_epi16(m_xv[27], 2), (UINT16)_mm_extract_epi16(m_xv[27], 1), (UINT16)_mm_extract_epi16(m_xv[27], 0)); + break; + case RSP_V28: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[28], 7), (UINT16)_mm_extract_epi16(m_xv[28], 6), (UINT16)_mm_extract_epi16(m_xv[28], 5), (UINT16)_mm_extract_epi16(m_xv[28], 4), (UINT16)_mm_extract_epi16(m_xv[28], 3), (UINT16)_mm_extract_epi16(m_xv[28], 2), (UINT16)_mm_extract_epi16(m_xv[28], 1), (UINT16)_mm_extract_epi16(m_xv[28], 0)); + break; + case RSP_V29: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[29], 7), (UINT16)_mm_extract_epi16(m_xv[29], 6), (UINT16)_mm_extract_epi16(m_xv[29], 5), (UINT16)_mm_extract_epi16(m_xv[29], 4), (UINT16)_mm_extract_epi16(m_xv[29], 3), (UINT16)_mm_extract_epi16(m_xv[29], 2), (UINT16)_mm_extract_epi16(m_xv[29], 1), (UINT16)_mm_extract_epi16(m_xv[29], 0)); + break; + case RSP_V30: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[30], 7), (UINT16)_mm_extract_epi16(m_xv[30], 6), (UINT16)_mm_extract_epi16(m_xv[30], 5), (UINT16)_mm_extract_epi16(m_xv[30], 4), (UINT16)_mm_extract_epi16(m_xv[30], 3), (UINT16)_mm_extract_epi16(m_xv[30], 2), (UINT16)_mm_extract_epi16(m_xv[30], 1), (UINT16)_mm_extract_epi16(m_xv[30], 0)); + break; + case RSP_V31: + string.printf("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", (UINT16)_mm_extract_epi16(m_xv[31], 7), (UINT16)_mm_extract_epi16(m_xv[31], 6), (UINT16)_mm_extract_epi16(m_xv[31], 5), (UINT16)_mm_extract_epi16(m_xv[31], 4), (UINT16)_mm_extract_epi16(m_xv[31], 3), (UINT16)_mm_extract_epi16(m_xv[31], 2), (UINT16)_mm_extract_epi16(m_xv[31], 1), (UINT16)_mm_extract_epi16(m_xv[31], 0)); + 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 + +inline void rsp_cop2_simd::lbv() +{ + UINT32 op = m_op; + + UINT32 ea = 0; + 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; + + UINT16 element; + EXTRACT16(m_xv[dest], element, (index >> 1)); + element &= 0xff00 >> ((1-(index & 1)) * 8); + element |= m_rsp.DM_READ8(ea) << ((1-(index & 1)) * 8); + INSERT16(m_xv[dest], element, (index >> 1)); +} + +static void cfunc_lbv(void *param) +{ + ((rsp_cop2 *)param)->lbv(); +} + + +// LSV +// +// 31 25 20 15 10 6 0 +// -------------------------------------------------- +// | 110010 | BBBBB | TTTTT | 00001 | IIII | Offset | +// -------------------------------------------------- +// +// Loads 2 bytes starting from vector byte index + +inline void rsp_cop2_simd::lsv() +{ + UINT32 op = m_op; + int dest = (op >> 16) & 0x1f; + int base = (op >> 21) & 0x1f; + int index = (op >> 7) & 0xe; + int offset = (op & 0x7f); + if (offset & 0x40) + { + offset |= 0xffffffc0; + } + + UINT32 ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 2) : (offset * 2); + int end = index + 2; + for (int i = index; i < end; i++) + { + UINT16 element; + EXTRACT16(m_xv[dest], element, (i >> 1)); + element &= 0xff00 >> ((1 - (i & 1)) * 8); + element |= m_rsp.DM_READ8(ea) << ((1 - (i & 1)) * 8); + INSERT16(m_xv[dest], element, (i >> 1)); + ea++; + } +} + +static void cfunc_lsv(void *param) +{ + ((rsp_cop2 *)param)->lsv(); +} + + +// LLV +// +// 31 25 20 15 10 6 0 +// -------------------------------------------------- +// | 110010 | BBBBB | TTTTT | 00010 | IIII | Offset | +// -------------------------------------------------- +// +// Loads 4 bytes starting from vector byte index + +inline void rsp_cop2_simd::llv() +{ + UINT32 op = m_op; + UINT32 ea = 0; + int dest = (op >> 16) & 0x1f; + int base = (op >> 21) & 0x1f; + int index = (op >> 7) & 0xc; + 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++) + { + UINT16 element; + EXTRACT16(m_xv[dest], element, (i >> 1)); + element &= 0xff00 >> ((1 - (i & 1)) * 8); + element |= m_rsp.DM_READ8(ea) << ((1 - (i & 1)) * 8); + INSERT16(m_xv[dest], element, (i >> 1)); + ea++; + } +} + +static void cfunc_llv(void *param) +{ + ((rsp_cop2 *)param)->llv(); +} +#endif + + +// LDV +// +// 31 25 20 15 10 6 0 +// -------------------------------------------------- +// | 110010 | BBBBB | TTTTT | 00011 | IIII | Offset | +// -------------------------------------------------- +// +// Loads 8 bytes starting from vector byte index + +inline void rsp_cop2_simd::ldv() +{ + UINT32 op = m_op; + UINT32 ea = 0; + int dest = (op >> 16) & 0x1f; + int base = (op >> 21) & 0x1f; + int index = (op >> 7) & 0x8; + 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++) + { + UINT16 element; + EXTRACT16(m_xv[dest], element, (i >> 1)); + element &= 0xff00 >> ((1 - (i & 1)) * 8); + element |= m_rsp.DM_READ8(ea) << ((1 - (i & 1)) * 8); + INSERT16(m_xv[dest], element, (i >> 1)); + ea++; + } +} + +static void cfunc_ldv(void *param) +{ + ((rsp_cop2 *)param)->ldv(); +} +#endif + + +// LQV +// +// 31 25 20 15 10 6 0 +// -------------------------------------------------- +// | 110010 | BBBBB | TTTTT | 00100 | IIII | Offset | +// -------------------------------------------------- +// +// Loads up to 16 bytes starting from vector byte index + +inline void rsp_cop2_simd::lqv() +{ + UINT32 op = m_op; + int dest = (op >> 16) & 0x1f; + int base = (op >> 21) & 0x1f; + int offset = (op & 0x7f); + if (offset & 0x40) + { + offset |= 0xffffffc0; + } + + UINT32 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++) + { + UINT16 element; + EXTRACT16(m_xv[dest], element, (i >> 1)); + element &= 0xff00 >> ((1 - (i & 1)) * 8); + element |= m_rsp.DM_READ8(ea) << ((1 - (i & 1)) * 8); + INSERT16(m_xv[dest], element, (i >> 1)); + ea++; + } +} + +static void cfunc_lqv(void *param) +{ + ((rsp_cop2 *)param)->lqv(); +} + + +// 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 + +inline void rsp_cop2_simd::lrv() +{ + UINT32 op = m_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 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++) + { + UINT16 element; + EXTRACT16(m_xv[dest], element, (i >> 1)); + element &= 0xff00 >> ((1-(i & 1)) * 8); + element |= m_rsp.DM_READ8(ea) << ((1-(i & 1)) * 8); + INSERT16(m_xv[dest], element, (i >> 1)); + ea++; + } +} + +static void cfunc_lrv(void *param) +{ + ((rsp_cop2 *)param)->lrv(); +} + + +// 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 + +inline void rsp_cop2_simd::lpv() +{ + UINT32 op = m_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 ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 8) : (offset * 8); + + for (int i = 0; i < 8; i++) + { + INSERT16(m_xv[dest], m_rsp.DM_READ8(ea + (((16-index) + i) & 0xf)) << 8, i); + } +} + +static void cfunc_lpv(void *param) +{ + ((rsp_cop2 *)param)->lpv(); +} + + +// 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 + +inline void rsp_cop2_simd::luv() +{ + UINT32 op = m_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 ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 8) : (offset * 8); + + for (int i = 0; i < 8; i++) + { + INSERT16(m_xv[dest], m_rsp.DM_READ8(ea + (((16-index) + i) & 0xf)) << 7, i); + } +} + +static void cfunc_luv(void *param) +{ + ((rsp_cop2 *)param)->luv(); +} + + +// 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 + +inline void rsp_cop2_simd::lhv() +{ + UINT32 op = m_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 ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); + + for (int i = 0; i < 8; i++) + { + INSERT16(m_xv[dest], m_rsp.DM_READ8(ea + (((16-index) + (i<<1)) & 0xf)) << 7, i); + } +} + +static void cfunc_lhv(void *param) +{ + ((rsp_cop2 *)param)->lhv(); +} + + +// 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 + +inline void rsp_cop2_simd::lfv() +{ + UINT32 op = m_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 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++) + { + INSERT16(m_xv[dest], m_rsp.DM_READ8(ea) << 7, i); + ea += 4; + } +} + +static void cfunc_lfv(void *param) +{ + ((rsp_cop2 *)param)->lfv(); +} + + +// 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 + +inline void rsp_cop2_simd::lwv() +{ + UINT32 op = m_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 ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); + int end = (16 - index) + 16; + + UINT8 val[16]; + for (int i = (16 - index); i < end; i++) + { + val[i & 0xf] = m_rsp.DM_READ8(ea); + ea += 4; + } + + m_xv[dest] = _mm_set_epi8(val[15], val[14], val[13], val[12], val[11], val[10], val[ 9], val[ 8], + val[ 7], val[ 6], val[ 5], val[ 4], val[ 3], val[ 2], val[ 1], val[ 0]); +} + +static void cfunc_lwv(void *param) +{ + ((rsp_cop2 *)param)->lwv(); +} + + +// 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 + +inline void rsp_cop2_simd::ltv() +{ + UINT32 op = m_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 = 7 - (index >> 1); + + UINT32 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; + UINT16 value = (m_rsp.DM_READ8(ea) << 8) | m_rsp.DM_READ8(ea + 1); + INSERT16(m_xv[i], value, (element >> 1)); + ea += 2; + } +} + +static void cfunc_ltv(void *param) +{ + ((rsp_cop2 *)param)->ltv(); +} + + +/*************************************************************************** + Vector Store Instructions +***************************************************************************/ + +// SBV +// +// 31 25 20 15 10 6 0 +// -------------------------------------------------- +// | 111010 | BBBBB | TTTTT | 00000 | IIII | Offset | +// -------------------------------------------------- +// +// Stores 1 byte from vector byte index + +inline void rsp_cop2_simd::sbv() +{ + UINT32 op = m_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 ea = (base) ? m_rsp.m_rsp_state->r[base] + offset : offset; + UINT16 value; + EXTRACT16(m_xv[dest], value, (index >> 1)); + value >>= (1-(index & 1)) * 8; + m_rsp.DM_WRITE8(ea, (UINT8)value); +} + +static void cfunc_sbv(void *param) +{ + ((rsp_cop2 *)param)->sbv(); +} + + +// SSV +// +// 31 25 20 15 10 6 0 +// -------------------------------------------------- +// | 111010 | BBBBB | TTTTT | 00001 | IIII | Offset | +// -------------------------------------------------- +// +// Stores 2 bytes starting from vector byte index + +inline void rsp_cop2_simd::ssv() +{ + UINT32 op = m_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 ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 2) : (offset * 2); + + int end = index + 2; + for (int i = index; i < end; i++) + { + UINT16 value; + EXTRACT16(m_xv[dest], value, (i >> 1)); + value >>= (1 - (i & 1)) * 8; + m_rsp.DM_WRITE8(ea, (UINT8)value); + ea++; + } +} + +static void cfunc_ssv(void *param) +{ + ((rsp_cop2 *)param)->ssv(); +} + + +// SLV +// +// 31 25 20 15 10 6 0 +// -------------------------------------------------- +// | 111010 | BBBBB | TTTTT | 00010 | IIII | Offset | +// -------------------------------------------------- +// +// Stores 4 bytes starting from vector byte index + +inline void rsp_cop2_simd::slv() +{ + UINT32 op = m_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 ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 4) : (offset * 4); + + int end = index + 4; + for (int i = index; i < end; i++) + { + UINT16 value; + EXTRACT16(m_xv[dest], value, (i >> 1)); + value >>= (1 - (i & 1)) * 8; + m_rsp.DM_WRITE8(ea, (UINT8)value); + ea++; + } +} + +static void cfunc_slv(void *param) +{ + ((rsp_cop2 *)param)->slv(); +} + + +// SDV +// +// 31 25 20 15 10 6 0 +// -------------------------------------------------- +// | 111010 | BBBBB | TTTTT | 00011 | IIII | Offset | +// -------------------------------------------------- +// +// Stores 8 bytes starting from vector byte index + +inline void rsp_cop2_simd::sdv() +{ + UINT32 op = m_op; + int dest = (op >> 16) & 0x1f; + int base = (op >> 21) & 0x1f; + int index = (op >> 7) & 0x8; + int offset = (op & 0x7f); + if (offset & 0x40) + { + offset |= 0xffffffc0; + } + UINT32 ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 8) : (offset * 8); + + int end = index + 8; + for (int i = index; i < end; i++) + { + UINT16 value; + EXTRACT16(m_xv[dest], value, (i >> 1)); + value >>= (1 - (i & 1)) * 8; + m_rsp.DM_WRITE8(ea, (UINT8)value); + ea++; + } +} + +static void cfunc_sdv(void *param) +{ + ((rsp_cop2 *)param)->sdv(); +} + + +// 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 + +inline void rsp_cop2_simd::sqv() +{ + UINT32 op = m_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 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++) + { + UINT16 value; + EXTRACT16(m_xv[dest], value, (i >> 1)); + value >>= (1-(i & 1)) * 8; + m_rsp.DM_WRITE8(ea, (UINT8)value); + ea++; + } +} + +static void cfunc_sqv(void *param) +{ + ((rsp_cop2 *)param)->sqv(); +} + + +// 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 + +inline void rsp_cop2_simd::srv() +{ + UINT32 op = m_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 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++) + { + UINT32 bi = (i + o) & 0xf; + UINT16 value; + EXTRACT16(m_xv[dest], value, (bi >> 1)); + value >>= (1-(bi & 1)) * 8; + m_rsp.DM_WRITE8(ea, (UINT8)value); + ea++; + } +} + +static void cfunc_srv(void *param) +{ + ((rsp_cop2 *)param)->srv(); +} + + +// SPV +// +// 31 25 20 15 10 6 0 +// -------------------------------------------------- +// | 111010 | BBBBB | TTTTT | 00110 | IIII | Offset | +// -------------------------------------------------- +// +// Stores upper 8 bits of each element + +inline void rsp_cop2_simd::spv() +{ + UINT32 op = m_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 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) + { + UINT16 value; + EXTRACT16(m_xv[dest], value, i); + m_rsp.DM_WRITE8(ea, (UINT8)(value >> 8)); + } + else + { + UINT16 value; + EXTRACT16(m_xv[dest], value, i); + m_rsp.DM_WRITE8(ea, (UINT8)(value >> 7)); + } + ea++; + } +} + +static void cfunc_spv(void *param) +{ + ((rsp_cop2 *)param)->spv(); +} + + +// SUV +// +// 31 25 20 15 10 6 0 +// -------------------------------------------------- +// | 111010 | BBBBB | TTTTT | 00111 | IIII | Offset | +// -------------------------------------------------- +// +// Stores bits 14-7 of each element + +inline void rsp_cop2_simd::suv() +{ + UINT32 op = m_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 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) + { + UINT16 value; + EXTRACT16(m_xv[dest], value, i); + m_rsp.DM_WRITE8(ea, (UINT8)(value >> 7)); + } + else + { + UINT16 value; + EXTRACT16(m_xv[dest], value, i); + m_rsp.DM_WRITE8(ea, (UINT8)(value >> 8)); + } + ea++; + } +} + +static void cfunc_suv(void *param) +{ + ((rsp_cop2 *)param)->suv(); +} + + +// 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 + +inline void rsp_cop2_simd::shv() +{ + UINT32 op = m_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 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); + UINT16 value; + EXTRACT16(m_xv[dest], value, element >> 1); + m_rsp.DM_WRITE8(ea, (value >> 7) & 0x00ff); + ea += 2; + } +} + +static void cfunc_shv(void *param) +{ + ((rsp_cop2 *)param)->shv(); +} + + +// 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 + +inline void rsp_cop2_simd::sfv() +{ + UINT32 op = m_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 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++) + { + UINT16 value; + EXTRACT16(m_xv[dest], value, i); + m_rsp.DM_WRITE8(ea + (eaoffset & 0xf), (value >> 7) & 0x00ff); + eaoffset += 4; + } +} + +static void cfunc_sfv(void *param) +{ + ((rsp_cop2 *)param)->sfv(); +} + + +// 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 + +inline void rsp_cop2_simd::swv() +{ + UINT32 op = m_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 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++) + { + UINT16 value; + EXTRACT16(m_xv[dest], value, i >> 1); + m_rsp.DM_WRITE8(ea + (eaoffset & 0xf), (value >> ((1-(i & 1)) * 8)) & 0xff); + eaoffset++; + } +} + +static void cfunc_swv(void *param) +{ + ((rsp_cop2 *)param)->swv(); +} + + +// 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 + +inline void rsp_cop2_simd::stv() +{ + UINT32 op = m_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 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++) + { + UINT16 value; + EXTRACT16(m_xv[i], value, element); + m_rsp.DM_WRITE16(ea + (eaoffset & 0xf), value); + eaoffset += 2; + element++; + } +} + +static void cfunc_stv(void *param) +{ + ((rsp_cop2 *)param)->stv(); +} + + +/*************************************************************************** + SIMD Accelerators +***************************************************************************/ + +/* ============================================================================ +* RSPPackLo32to16: Pack LSBs of 32-bit vectors to 16-bits without saturation. +* TODO: 5 SSE2 operations is kind of expensive just to truncate values? +* ========================================================================= */ +INLINE __m128i RSPPackLo32to16(__m128i vectorLow, __m128i vectorHigh) +{ + vectorLow = _mm_slli_epi32(vectorLow, 16); + vectorHigh = _mm_slli_epi32(vectorHigh, 16); + vectorLow = _mm_srai_epi32(vectorLow, 16); + vectorHigh = _mm_srai_epi32(vectorHigh, 16); + return _mm_packs_epi32(vectorLow, vectorHigh); +} + +/* ============================================================================ +* RSPPackHi32to16: Pack MSBs of 32-bit vectors to 16-bits without saturation. +* ========================================================================= */ +INLINE __m128i RSPPackHi32to16(__m128i vectorLow, __m128i vectorHigh) +{ + vectorLow = _mm_srai_epi32(vectorLow, 16); + vectorHigh = _mm_srai_epi32(vectorHigh, 16); + return _mm_packs_epi32(vectorLow, vectorHigh); +} + +/* ============================================================================ +* RSPSignExtend16to32: Sign-extend 16-bit slices to 32-bit slices. +* ========================================================================= */ +INLINE void RSPSignExtend16to32(__m128i source, __m128i *vectorLow, __m128i *vectorHigh) +{ + __m128i vMask = _mm_srai_epi16(source, 15); + *vectorHigh = _mm_unpackhi_epi16(source, vMask); + *vectorLow = _mm_unpacklo_epi16(source, vMask); +} + +/* ============================================================================ +* RSPZeroExtend16to32: Zero-extend 16-bit slices to 32-bit slices. +* ========================================================================= */ +INLINE void RSPZeroExtend16to32(__m128i source, __m128i *vectorLow, __m128i *vectorHigh) +{ + *vectorHigh = _mm_unpackhi_epi16(source, _mm_setzero_si128()); + *vectorLow = _mm_unpacklo_epi16(source, _mm_setzero_si128()); +} + +/* ============================================================================ +* _mm_mullo_epi32: SSE2 lacks _mm_mullo_epi32, define it manually. +* TODO/WARNING/DISCLAIMER: Assumes one argument is positive. +* ========================================================================= */ +INLINE __m128i _mm_mullo_epi32(__m128i a, __m128i b) +{ + __m128i a4 = _mm_srli_si128(a, 4); + __m128i b4 = _mm_srli_si128(b, 4); + __m128i ba = _mm_mul_epu32(b, a); + __m128i b4a4 = _mm_mul_epu32(b4, a4); + + __m128i mask = _mm_setr_epi32(~0, 0, ~0, 0); + __m128i baMask = _mm_and_si128(ba, mask); + __m128i b4a4Mask = _mm_and_si128(b4a4, mask); + __m128i b4a4MaskShift = _mm_slli_si128(b4a4Mask, 4); + + return _mm_or_si128(baMask, b4a4MaskShift); +} + +/* ============================================================================ +* RSPClampLowToVal: Clamps the low word of the accumulator. +* ========================================================================= */ +INLINE __m128i RSPClampLowToVal(__m128i vaccLow, __m128i vaccMid, __m128i vaccHigh) +{ + __m128i setMask = _mm_cmpeq_epi16(_mm_setzero_si128(), _mm_setzero_si128()); + __m128i negCheck, useValMask, negVal, posVal; + + /* Compute some common values ahead of time. */ + negCheck = _mm_cmplt_epi16(vaccHigh, _mm_setzero_si128()); + + /* If accmulator < 0, clamp to val if val != TMin. */ + useValMask = _mm_and_si128(vaccHigh, _mm_srai_epi16(vaccMid, 15)); + useValMask = _mm_cmpeq_epi16(useValMask, setMask); + negVal = _mm_and_si128(useValMask, vaccLow); + + /* Otherwise, clamp to ~0 if any high bits are set. */ + useValMask = _mm_or_si128(vaccHigh, _mm_srai_epi16(vaccMid, 15)); + useValMask = _mm_cmpeq_epi16(useValMask, _mm_setzero_si128()); + posVal = _mm_and_si128(useValMask, vaccLow); + + negVal = _mm_and_si128(negCheck, negVal); + posVal = _mm_andnot_si128(negCheck, posVal); + return _mm_or_si128(negVal, posVal); +} + + +/*************************************************************************** + 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 + +inline void rsp_cop2_simd::vmulf() +{ + int op = m_op; + + for (int i = 0; i < 8; i++) + { + UINT16 w1, w2; + GET_VS1(w1, i); + GET_VS2(w2, i); + INT32 s1 = (INT32)(INT16)w1; + INT32 s2 = (INT32)(INT16)w2; + + 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 r = s1 * s2 * 2; + r += 0x8000; // rounding ? + SET_ACCUM_H((r < 0) ? 0xffff : 0, i); + SET_ACCUM_M((INT16)(r >> 16), i); + SET_ACCUM_L((UINT16)(r), i); + m_vres[i] = ACCUM_M(i); + } + } + WRITEBACK_RESULT(); +} + +static void cfunc_vmulf(void *param) +{ + ((rsp_cop2 *)param)->vmulf(); +} + + +// VMULU +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000001 | +// ------------------------------------------------------ +// + +inline void rsp_cop2_simd::vmulu() +{ + int op = m_op; + + for (int i = 0; i < 8; i++) + { + UINT16 w1, w2; + GET_VS1(w1, i); + GET_VS2(w2, i); + INT32 s1 = (INT32)(INT16)w1; + INT32 s2 = (INT32)(INT16)w2; + + INT64 r = s1 * s2 * 2; + r += 0x8000; // rounding ? + + SET_ACCUM_H((UINT16)(r >> 32), i); + SET_ACCUM_M((UINT16)(r >> 16), i); + SET_ACCUM_L((UINT16)(r), i); + + if (r < 0) + { + m_vres[i] = 0; + } + else if (((INT16)(ACCUM_H(i)) ^ (INT16)(ACCUM_M(i))) < 0) + { + m_vres[i] = -1; + } + else + { + m_vres[i] = ACCUM_M(i); + } + } + WRITEBACK_RESULT(); +} + +static void cfunc_vmulu(void *param) +{ + ((rsp_cop2 *)param)->vmulu(); +} + + +// 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 + +inline void rsp_cop2_simd::vmudl() +{ + int op = m_op; + + __m128i vsReg = m_xv[VS1REG]; + __m128i vtReg = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); + + /* Unpack to obtain for 32-bit precision. */ + __m128i unpackLo = _mm_mullo_epi16(vsReg, vtReg); + __m128i unpackHi = _mm_mulhi_epu16(vsReg, vtReg); + __m128i loProduct = _mm_unpacklo_epi16(unpackLo, unpackHi); + __m128i hiProduct = _mm_unpackhi_epi16(unpackLo, unpackHi); + + m_xv[VDREG] = m_accum_l = RSPPackHi32to16(loProduct, hiProduct); + + m_accum_m = _mm_setzero_si128(); + m_accum_h = _mm_setzero_si128(); +} + +static void cfunc_vmudl(void *param) +{ + ((rsp_cop2 *)param)->vmudl(); +} + + +// 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 + +inline void rsp_cop2_simd::vmudm() +{ + int op = m_op; + + __m128i vsRegLo, vsRegHi, vtRegLo, vtRegHi; + + __m128i vsReg = m_xv[VS1REG]; + __m128i vtReg = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); + + /* Unpack to obtain for 32-bit precision. */ + RSPSignExtend16to32(vsReg, &vsRegLo, &vsRegHi); + RSPZeroExtend16to32(vtReg, &vtRegLo, &vtRegHi); + + /* Begin accumulating the products. */ + __m128i loProduct = _mm_mullo_epi32(vsRegLo, vtRegLo); + __m128i hiProduct = _mm_mullo_epi32(vsRegHi, vtRegHi); + m_accum_l = RSPPackLo32to16(loProduct, hiProduct); + m_accum_m = m_xv[VDREG] = RSPPackHi32to16(loProduct, hiProduct); + + loProduct = _mm_cmplt_epi32(loProduct, _mm_setzero_si128()); + hiProduct = _mm_cmplt_epi32(hiProduct, _mm_setzero_si128()); + m_accum_h = _mm_packs_epi32(loProduct, hiProduct); +} + +static void cfunc_vmudm(void *param) +{ + ((rsp_cop2 *)param)->vmudm(); +} + + +// 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 + +inline void rsp_cop2_simd::vmudn() +{ + int op = m_op; + + __m128i vsRegLo, vsRegHi, vtRegLo, vtRegHi; + + __m128i vsReg = m_xv[VS1REG]; + __m128i vtReg = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); + + /* Unpack to obtain for 32-bit precision. */ + RSPZeroExtend16to32(vsReg, &vsRegLo, &vsRegHi); + RSPSignExtend16to32(vtReg, &vtRegLo, &vtRegHi); + + /* Begin accumulating the products. */ + __m128i loProduct = _mm_mullo_epi32(vsRegLo, vtRegLo); + __m128i hiProduct = _mm_mullo_epi32(vsRegHi, vtRegHi); + m_xv[VDREG] = m_accum_l = RSPPackLo32to16(loProduct, hiProduct); + m_accum_m = RSPPackHi32to16(loProduct, hiProduct); + m_accum_h = _mm_cmplt_epi16(m_accum_m, _mm_setzero_si128()); +} + +static void cfunc_vmudn(void *param) +{ + ((rsp_cop2 *)param)->vmudn(); +} + + +// 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 + +inline void rsp_cop2_simd::vmudh() +{ + int op = m_op; + + __m128i vaccLow, vaccHigh; + __m128i unpackLo, unpackHi; + + __m128i vsReg = m_xv[VS1REG]; + __m128i vtReg = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); + + /* Multiply the sources, accumulate the product. */ + unpackLo = _mm_mullo_epi16(vsReg, vtReg); + unpackHi = _mm_mulhi_epi16(vsReg, vtReg); + vaccHigh = _mm_unpackhi_epi16(unpackLo, unpackHi); + vaccLow = _mm_unpacklo_epi16(unpackLo, unpackHi); + + /* Pack the accumulator and result back up. */ + m_xv[VDREG] = _mm_packs_epi32(vaccLow, vaccHigh); + m_accum_l = _mm_setzero_si128(); + m_accum_m = RSPPackLo32to16(vaccLow, vaccHigh); + m_accum_h = RSPPackHi32to16(vaccLow, vaccHigh); +} + +static void cfunc_vmudh(void *param) +{ + ((rsp_cop2 *)param)->vmudh(); +} + + +// VMACF +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001000 | +// ------------------------------------------------------ +// + +inline void rsp_cop2_simd::vmacf() +{ + int op = m_op; + + for (int i = 0; i < 8; i++) + { + UINT16 w1, w2; + GET_VS1(w1, i); + GET_VS2(w2, i); + INT32 s1 = (INT32)(INT16)w1; + INT32 s2 = (INT32)(INT16)w2; + + INT32 r = s1 * s2; + + UINT64 q = (UINT64)(UINT16)ACCUM_LL(i); + q |= (((UINT64)(UINT16)ACCUM_L(i)) << 16); + q |= (((UINT64)(UINT16)ACCUM_M(i)) << 32); + q |= (((UINT64)(UINT16)ACCUM_H(i)) << 48); + + q += (INT64)(r) << 17; + SET_ACCUM_LL((UINT16)q, i); + SET_ACCUM_L((UINT16)(q >> 16), i); + SET_ACCUM_M((UINT16)(q >> 32), i); + SET_ACCUM_H((UINT16)(q >> 48), i); + + m_vres[i] = SATURATE_ACCUM(i, 1, 0x8000, 0x7fff); + } + WRITEBACK_RESULT(); +} + +static void cfunc_vmacf(void *param) +{ + ((rsp_cop2 *)param)->vmacf(); +} + + +// VMACU +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001001 | +// ------------------------------------------------------ +// + +inline void rsp_cop2_simd::vmacu() +{ + int op = m_op; + + __m128i loProduct, hiProduct, unpackLo, unpackHi; + __m128i vaccHigh; + __m128i vdReg, vdRegLo, vdRegHi; + + __m128i vsReg = m_xv[VS1REG]; + __m128i vtReg = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); + + __m128i vaccLow = m_accum_l; + + /* Unpack to obtain for 32-bit precision. */ + RSPZeroExtend16to32(vaccLow, &vaccLow, &vaccHigh); + + /* Begin accumulating the products. */ + unpackLo = _mm_mullo_epi16(vsReg, vtReg); + unpackHi = _mm_mulhi_epi16(vsReg, vtReg); + loProduct = _mm_unpacklo_epi16(unpackLo, unpackHi); + hiProduct = _mm_unpackhi_epi16(unpackLo, unpackHi); + loProduct = _mm_slli_epi32(loProduct, 1); + hiProduct = _mm_slli_epi32(hiProduct, 1); + + vdRegLo = _mm_srli_epi32(loProduct, 16); + vdRegHi = _mm_srli_epi32(hiProduct, 16); + vdRegLo = _mm_slli_epi32(vdRegLo, 16); + vdRegHi = _mm_slli_epi32(vdRegHi, 16); + vdRegLo = _mm_xor_si128(vdRegLo, loProduct); + vdRegHi = _mm_xor_si128(vdRegHi, hiProduct); + + vaccLow = _mm_add_epi32(vaccLow, vdRegLo); + vaccHigh = _mm_add_epi32(vaccHigh, vdRegHi); + + m_accum_l = vdReg = RSPPackLo32to16(vaccLow, vaccHigh); + + /* Multiply the MSB of sources, accumulate the product. */ + vdRegLo = _mm_unpacklo_epi16(m_accum_m, m_accum_h); + vdRegHi = _mm_unpackhi_epi16(m_accum_m, m_accum_h); + + loProduct = _mm_srai_epi32(loProduct, 16); + hiProduct = _mm_srai_epi32(hiProduct, 16); + vaccLow = _mm_srai_epi32(vaccLow, 16); + vaccHigh = _mm_srai_epi32(vaccHigh, 16); + + vaccLow = _mm_add_epi32(loProduct, vaccLow); + vaccHigh = _mm_add_epi32(hiProduct, vaccHigh); + vaccLow = _mm_add_epi32(vdRegLo, vaccLow); + vaccHigh = _mm_add_epi32(vdRegHi, vaccHigh); + + /* Clamp the accumulator and write it all out. */ + m_accum_m = RSPPackLo32to16(vaccLow, vaccHigh); + m_accum_h = RSPPackHi32to16(vaccLow, vaccHigh); +} + +static void cfunc_vmacu(void *param) +{ + ((rsp_cop2 *)param)->vmacu(); +} + + +// 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 + +inline void rsp_cop2_simd::vmadl() +{ + int op = m_op; + + for (int i = 0; i < 8; i++) + { + UINT16 w1, w2; + GET_VS1(w1, i); + GET_VS2(w2, i); + UINT32 s1 = w1; + UINT32 s2 = w2; + + UINT32 r1 = s1 * s2; + UINT32 r2 = (UINT16)ACCUM_L(i) + (r1 >> 16); + UINT32 r3 = (UINT16)ACCUM_M(i) + (r2 >> 16); + + SET_ACCUM_L((UINT16)r2, i); + SET_ACCUM_M((UINT16)r3, i); + SET_ACCUM_H(ACCUM_H(i) + (INT16)(r3 >> 16), i); + + m_vres[i] = SATURATE_ACCUM(i, 0, 0x0000, 0xffff); + } + WRITEBACK_RESULT(); +} + +static void cfunc_vmadl(void *param) +{ + ((rsp_cop2 *)param)->vmadl(); +} + + +// VMADM +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001101 | +// ------------------------------------------------------ +// +// Multiplies signed fraction by unsigned fraction +// Adds the higher 16 bits of the 32-bit result to accumulator +// The medium slice of accumulator is stored into destination element + +inline void rsp_cop2_simd::vmadm() +{ + int op = m_op; + + __m128i vaccLow, vaccHigh, loProduct, hiProduct; + __m128i vsRegLo, vsRegHi, vtRegLo, vtRegHi, vdRegLo, vdRegHi; + + __m128i vsReg = m_xv[VS1REG]; + __m128i vtReg = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); + + /* Unpack to obtain for 32-bit precision. */ + RSPSignExtend16to32(vsReg, &vsRegLo, &vsRegHi); + RSPZeroExtend16to32(vtReg, &vtRegLo, &vtRegHi); + RSPZeroExtend16to32(m_accum_l, &vaccLow, &vaccHigh); + + /* Begin accumulating the products. */ + loProduct = _mm_mullo_epi32(vsRegLo, vtRegLo); + hiProduct = _mm_mullo_epi32(vsRegHi, vtRegHi); + + vdRegLo = _mm_srli_epi32(loProduct, 16); + vdRegHi = _mm_srli_epi32(hiProduct, 16); + vdRegLo = _mm_slli_epi32(vdRegLo, 16); + vdRegHi = _mm_slli_epi32(vdRegHi, 16); + vdRegLo = _mm_xor_si128(vdRegLo, loProduct); + vdRegHi = _mm_xor_si128(vdRegHi, hiProduct); + vaccLow = _mm_add_epi32(vaccLow, vdRegLo); + vaccHigh = _mm_add_epi32(vaccHigh, vdRegHi); + + m_accum_l = m_xv[VDREG] = RSPPackLo32to16(vaccLow, vaccHigh); + + /* Multiply the MSB of sources, accumulate the product. */ + vdRegLo = _mm_unpacklo_epi16(m_accum_m, m_accum_h); + vdRegHi = _mm_unpackhi_epi16(m_accum_m, m_accum_h); + + loProduct = _mm_srai_epi32(loProduct, 16); + hiProduct = _mm_srai_epi32(hiProduct, 16); + vaccLow = _mm_srai_epi32(vaccLow, 16); + vaccHigh = _mm_srai_epi32(vaccHigh, 16); + + vaccLow = _mm_add_epi32(loProduct, vaccLow); + vaccHigh = _mm_add_epi32(hiProduct, vaccHigh); + vaccLow = _mm_add_epi32(vdRegLo, vaccLow); + vaccHigh = _mm_add_epi32(vdRegHi, vaccHigh); + + /* Clamp the accumulator and write it all out. */ + m_xv[VDREG] = _mm_packs_epi32(vaccLow, vaccHigh); + m_accum_m = RSPPackLo32to16(vaccLow, vaccHigh); + m_accum_h = RSPPackHi32to16(vaccLow, vaccHigh); +} + +static void cfunc_vmadm(void *param) +{ + ((rsp_cop2 *)param)->vmadm(); +} + + +// VMADN +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001110 | +// ------------------------------------------------------ +// +// Multiplies unsigned fraction by signed fraction +// Adds the 32-bit result to the medium and high slices of the accumulator +// The low slice of accumulator is saturated into destination element + +inline void rsp_cop2_simd::vmadn() +{ + int op = m_op; + + for (int i = 0; i < 8; i++) + { + UINT16 w1, w2; + GET_VS1(w1, i); + GET_VS2(w2, i); + INT32 s1 = (UINT16)w1; + INT32 s2 = (INT32)(INT16)w2; + + UINT64 q = (UINT64)ACCUM_LL(i); + q |= (((UINT64)ACCUM_L(i)) << 16); + q |= (((UINT64)ACCUM_M(i)) << 32); + q |= (((UINT64)ACCUM_H(i)) << 48); + q += (INT64)(s1*s2) << 16; + + SET_ACCUM_LL((UINT16)q, i); + SET_ACCUM_L((UINT16)(q >> 16), i); + SET_ACCUM_M((UINT16)(q >> 32), i); + SET_ACCUM_H((UINT16)(q >> 48), i); + + m_vres[i] = SATURATE_ACCUM(i, 0, 0x0000, 0xffff); + } + WRITEBACK_RESULT(); +} + +static void cfunc_vmadn(void *param) +{ + ((rsp_cop2 *)param)->vmadn(); +} + + +// 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 + +inline void rsp_cop2_simd::vmadh() +{ + int op = m_op; + + __m128i vsReg = m_xv[VS1REG]; + __m128i vtReg = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); + + /* Unpack to obtain for 32-bit precision. */ + __m128i vaccLow = _mm_unpacklo_epi16(m_accum_m, m_accum_h); + __m128i vaccHigh = _mm_unpackhi_epi16(m_accum_m, m_accum_h); + + /* Multiply the sources, accumulate the product. */ + __m128i unpackLo = _mm_mullo_epi16(vsReg, vtReg); + __m128i unpackHi = _mm_mulhi_epi16(vsReg, vtReg); + __m128i loProduct = _mm_unpacklo_epi16(unpackLo, unpackHi); + __m128i hiProduct = _mm_unpackhi_epi16(unpackLo, unpackHi); + vaccLow = _mm_add_epi32(vaccLow, loProduct); + vaccHigh = _mm_add_epi32(vaccHigh, hiProduct); + + /* Pack the accumulator and result back up. */ + m_xv[VDREG] = _mm_packs_epi32(vaccLow, vaccHigh); + m_accum_m = RSPPackLo32to16(vaccLow, vaccHigh); + m_accum_h = RSPPackHi32to16(vaccLow, vaccHigh); +} + +static void cfunc_vmadh(void *param) +{ + ((rsp_cop2 *)param)->vmadh(); +} + + +// 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 + +inline void rsp_cop2_simd::vadd() +{ + int op = m_op; + + __m128i shuffled = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); + __m128i carry = _mm_and_si128(m_xvflag[CARRY], vec_flagmask); + m_accum_l = _mm_add_epi16(_mm_add_epi16(m_xv[VS1REG], shuffled), carry); + + __m128i addvec = _mm_adds_epi16(m_xv[VS1REG], shuffled); + + carry = _mm_and_si128(carry, _mm_xor_si128(_mm_cmpeq_epi16(addvec, vec_32767), vec_neg1)); + carry = _mm_and_si128(carry, _mm_xor_si128(_mm_cmpeq_epi16(addvec, vec_n32768), vec_neg1)); + + m_xv[VDREG] = _mm_add_epi16(addvec, carry); + + m_xvflag[ZERO] = vec_zero; + m_xvflag[CARRY] = vec_zero; +} + +static void cfunc_vadd(void *param) +{ + ((rsp_cop2 *)param)->vadd(); +} + + +// 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 + +inline void rsp_cop2_simd::vsub() +{ + int op = m_op; + + __m128i shuffled = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); + __m128i carry = _mm_and_si128(m_xvflag[CARRY], vec_flagmask); + __m128i unsat = _mm_sub_epi16(m_xv[VS1REG], shuffled); + + __m128i vs2neg = _mm_cmplt_epi16(shuffled, vec_zero); + __m128i vs2pos = _mm_cmpeq_epi16(vs2neg, vec_zero); + + __m128i saturated = _mm_subs_epi16(m_xv[VS1REG], shuffled); + __m128i carry_mask = _mm_cmpeq_epi16(unsat, saturated); + carry_mask = _mm_and_si128(vs2neg, carry_mask); + + vs2neg = _mm_and_si128(carry_mask, carry); + vs2pos = _mm_and_si128(vs2pos, carry); + __m128i dest_carry = _mm_or_si128(vs2neg, vs2pos); + m_xv[VDREG] = _mm_subs_epi16(saturated, dest_carry); + + m_accum_l = _mm_sub_epi16(unsat, carry); + + m_xvflag[ZERO] = _mm_setzero_si128(); + m_xvflag[CARRY] = _mm_setzero_si128(); +} + +static void cfunc_vsub(void *param) +{ + ((rsp_cop2 *)param)->vsub(); +} + + +// 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 + +inline void rsp_cop2_simd::vabs() +{ + int op = m_op; + + __m128i shuf2 = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); + __m128i negs2 = _mm_sub_epi16(_mm_setzero_si128(), shuf2); + __m128i s2_n32768 = _mm_cmpeq_epi16(shuf2, vec_n32768); + __m128i s1_lz = _mm_cmplt_epi16(m_xv[VS1REG], _mm_setzero_si128()); + + __m128i result_gz = _mm_and_si128(shuf2, _mm_cmpgt_epi16(m_xv[VS1REG], _mm_setzero_si128())); + __m128i result_n32768 = _mm_and_si128(s1_lz, _mm_and_si128(vec_32767, s2_n32768)); + __m128i result_negs2 = _mm_and_si128(s1_lz, _mm_and_si128(negs2, _mm_xor_si128(s2_n32768, vec_neg1))); + m_xv[VDREG] = m_accum_l = _mm_or_si128(result_gz, _mm_or_si128(result_n32768, result_negs2)); +} + +static void cfunc_vabs(void *param) +{ + ((rsp_cop2 *)param)->vabs(); +} + + +// 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 + +inline void rsp_cop2_simd::vaddc() +{ + int op = m_op; + + CLEAR_ZERO_FLAGS(); + CLEAR_CARRY_FLAGS(); + + __m128i shuf2 = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); + __m128i vec7531 = _mm_and_si128(m_xv[VS1REG], vec_lomask); + __m128i vec6420 = _mm_srli_epi32(m_xv[VS1REG], 16); + __m128i shuf7531 = _mm_and_si128(shuf2, vec_lomask); + __m128i shuf6420 = _mm_srli_epi32(shuf2, 16); + __m128i sum7531 = _mm_add_epi32(vec7531, shuf7531); + __m128i sum6420 = _mm_add_epi32(vec6420, shuf6420); + + __m128i over7531 = _mm_and_si128(_mm_xor_si128(_mm_cmpeq_epi16(sum7531, _mm_setzero_si128()), vec_neg1), vec_himask); + __m128i over6420 = _mm_and_si128(_mm_xor_si128(_mm_cmpeq_epi16(sum6420, _mm_setzero_si128()), vec_neg1), vec_himask); + + sum7531 = _mm_and_si128(sum7531, vec_lomask); + sum6420 = _mm_and_si128(sum6420, vec_lomask); + + m_xvflag[CARRY] = _mm_or_si128(over6420, _mm_srli_epi32(over7531, 16)); + m_accum_l = m_xv[VDREG] = _mm_or_si128(_mm_slli_epi32(sum6420, 16), sum7531); +} + +static void cfunc_vaddc(void *param) +{ + ((rsp_cop2 *)param)->vaddc(); +} + + +// 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 + +inline void rsp_cop2_simd::vsubc() +{ + int op = m_op; + + CLEAR_ZERO_FLAGS(); + CLEAR_CARRY_FLAGS(); + + __m128i shuf2 = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); + __m128i vec7531 = _mm_and_si128(m_xv[VS1REG], vec_lomask); + __m128i vec6420 = _mm_srli_epi32(m_xv[VS1REG], 16); + __m128i shuf7531 = _mm_and_si128(shuf2, vec_lomask); + __m128i shuf6420 = _mm_srli_epi32(shuf2, 16); + __m128i sum7531 = _mm_sub_epi32(vec7531, shuf7531); + __m128i sum6420 = _mm_sub_epi32(vec6420, shuf6420); + + __m128i over7531 = _mm_and_si128(_mm_xor_si128(_mm_cmpeq_epi16(sum7531, _mm_setzero_si128()), vec_neg1), vec_himask); + __m128i over6420 = _mm_and_si128(_mm_xor_si128(_mm_cmpeq_epi16(sum6420, _mm_setzero_si128()), vec_neg1), vec_himask); + sum7531 = _mm_and_si128(sum7531, vec_lomask); + sum6420 = _mm_and_si128(sum6420, vec_lomask); + __m128i zero7531 = _mm_and_si128(_mm_xor_si128(_mm_cmpeq_epi16(sum7531, _mm_setzero_si128()), vec_neg1), vec_lomask); + __m128i zero6420 = _mm_and_si128(_mm_xor_si128(_mm_cmpeq_epi16(sum6420, _mm_setzero_si128()), vec_neg1), vec_lomask); + + m_xvflag[CARRY] = _mm_or_si128(over6420, _mm_srli_epi32(over7531, 16)); + m_xvflag[ZERO] = _mm_or_si128(_mm_slli_epi32(zero6420, 16), zero7531); + + m_accum_l = m_xv[VDREG] = _mm_or_si128(_mm_slli_epi32(sum6420, 16), sum7531); +} + +static void cfunc_vsubc(void *param) +{ + ((rsp_cop2 *)param)->vsubc(); +} + + +// VADDB +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 010110 | +// ------------------------------------------------------ +// +// Adds two vector registers bytewise with rounding +inline void rsp_cop2_simd::vaddb() +{ + const int op = m_op; + const int round = (EL == 0) ? 0 : (1 << (EL - 1)); + + for (int i = 0; i < 8; i++) + { + UINT16 w1, w2; + GET_VS1(w1, i); + GET_VS2(w2, i); + + UINT8 hb1 = w1 >> 8; + UINT8 lb1 = w1 & 0xff; + UINT8 hb2 = w2 >> 8; + UINT8 lb2 = w2 & 0xff; + + UINT16 hs = hb1 + hb2 + round; + UINT16 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(); +} + +static void cfunc_vaddb(void *param) +{ + ((rsp_cop2 *)param)->vaddb(); +} + + +// 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 + +inline void rsp_cop2_simd::vsaw() +{ + int op = m_op; + + switch (EL) + { + case 0x08: // VSAWH + { + m_xv[VDREG] = m_accum_h; + break; + } + case 0x09: // VSAWM + { + m_xv[VDREG] = m_accum_m; + break; + } + case 0x0a: // VSAWL + { + m_xv[VDREG] = m_accum_l; + break; + } + default: // Unsupported, writes 0 to VD + { + + } + } +} + +static void cfunc_vsaw(void *param) +{ + ((rsp_cop2 *)param)->vsaw(); +} + + +// 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 + +inline void rsp_cop2_simd::vlt() +{ + int op = m_op; + + m_xvflag[COMPARE] = m_xvflag[CLIP2] = _mm_setzero_si128(); + + __m128i shuf = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); + __m128i zc_mask = _mm_and_si128(m_xvflag[ZERO], m_xvflag[CARRY]); + __m128i lt_mask = _mm_cmplt_epi16(m_xv[VS1REG], shuf); + __m128i eq_mask = _mm_and_si128(_mm_cmpeq_epi16(m_xv[VS1REG], shuf), zc_mask); + + m_xvflag[COMPARE] = _mm_or_si128(lt_mask, eq_mask); + + __m128i result = _mm_and_si128(m_xv[VS1REG], m_xvflag[COMPARE]); + m_accum_l = m_xv[VDREG] = _mm_or_si128(result, _mm_and_si128(shuf, _mm_xor_si128(m_xvflag[COMPARE], vec_neg1))); + + m_xvflag[ZERO] = m_xvflag[CARRY] = _mm_setzero_si128(); +} + +static void cfunc_void vlt(void *param) +{ + ((rsp_cop2 *)param)->vlt(); +} + + +// 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 + +inline void rsp_cop2_simd::veq() +{ + int op = m_op; + + m_xvflag[COMPARE] = m_xvflag[CLIP2] = _mm_setzero_si128(); + + __m128i shuf = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); + __m128i zero_mask = _mm_cmpeq_epi16(m_xvflag[ZERO], _mm_setzero_si128()); + __m128i eq_mask = _mm_cmpeq_epi16(m_xv[VS1REG], shuf); + + m_xvflag[COMPARE] = _mm_and_si128(zero_mask, eq_mask); + + __m128i result = _mm_and_si128(m_xv[VS1REG], m_xvflag[COMPARE]); + m_accum_l = m_xv[VDREG] = _mm_or_si128(result, _mm_and_si128(shuf, _mm_xor_si128(m_xvflag[COMPARE], vec_neg1))); + + m_xvflag[ZERO] = m_xvflag[CARRY] = _mm_setzero_si128(); +} + +static void cfunc_veq(void *param) +{ + ((rsp_cop2 *)param)->veq(); +} + + +// 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 + +inline void rsp_cop2_simd::vne() +{ + int op = m_op; + + m_xvflag[COMPARE] = m_xvflag[CLIP2] = _mm_setzero_si128(); + + __m128i shuf = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); + __m128i neq_mask = _mm_xor_si128(_mm_cmpeq_epi16(m_xv[VS1REG], shuf), vec_neg1); + + m_xvflag[COMPARE] = _mm_or_si128(m_xvflag[ZERO], neq_mask); + + __m128i result = _mm_and_si128(m_xv[VS1REG], m_xvflag[COMPARE]); + m_accum_l = m_xv[VDREG] = _mm_or_si128(result, _mm_and_si128(shuf, _mm_xor_si128(m_xvflag[COMPARE], vec_neg1))); + + m_xvflag[ZERO] = m_xvflag[CARRY] = _mm_setzero_si128(); +} + +static void cfunc_vne(void *param) +{ + ((rsp_cop2 *)param)->vne(); +} + + +// 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 + +inline void rsp_cop2_simd::vge() +{ + int op = m_op; + + m_xvflag[COMPARE] = m_xvflag[CLIP2] = _mm_setzero_si128(); + + __m128i shuf = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); + __m128i zero_mask = _mm_cmpeq_epi16(m_xvflag[ZERO], _mm_setzero_si128()); + __m128i carry_mask = _mm_cmpeq_epi16(m_xvflag[CARRY], _mm_setzero_si128()); + __m128i flag_mask = _mm_or_si128(zero_mask, carry_mask); + __m128i eq_mask = _mm_and_si128(_mm_cmpeq_epi16(m_xv[VS1REG], shuf), flag_mask); + __m128i gt_mask = _mm_cmpgt_epi16(m_xv[VS1REG], shuf); + m_xvflag[COMPARE] = _mm_or_si128(eq_mask, gt_mask); + + __m128i result = _mm_and_si128(m_xv[VS1REG], m_xvflag[COMPARE]); + m_accum_l = m_xv[VDREG] = _mm_or_si128(result, _mm_and_si128(shuf, _mm_xor_si128(m_xvflag[COMPARE], vec_neg1))); + + m_xvflag[ZERO] = m_xvflag[CARRY] = _mm_setzero_si128(); +} + +static void cfunc_vge(void *param) +{ + ((rsp_cop2 *)param)->vge(); +} + + +// VCL +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100100 | +// ------------------------------------------------------ +// +// Vector clip low + +inline void rsp_cop2_simd::vcl() +{ + int op = m_op; + + for (int i = 0; i < 8; i++) + { + INT16 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)s2, i); + } + else + { + SET_ACCUM_L(s1, i); + } + } + else + { + if (CLIP1_FLAG(i) != 0) + { + if (((UINT32)(UINT16)(s1) + (UINT32)(UINT16)(s2)) > 0x10000) + { + SET_ACCUM_L(s1, i); + CLEAR_COMPARE_FLAG(i); + } + else + { + SET_ACCUM_L(-((UINT16)s2), i); + SET_COMPARE_FLAG(i); + } + } + else + { + if (((UINT32)(UINT16)(s1) + (UINT32)(UINT16)(s2)) != 0) + { + SET_ACCUM_L(s1, i); + CLEAR_COMPARE_FLAG(i); + } + else + { + SET_ACCUM_L(-((UINT16)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)(UINT16)s1 - (INT32)(UINT16)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(); +} + +static void cfunc_vcl(void *param) +{ + ((rsp_cop2 *)param)->vcl(); +} + + +// VCH +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100101 | +// ------------------------------------------------------ +// +// Vector clip high + +inline void rsp_cop2_simd::vch() +{ + int op = m_op; + + CLEAR_CARRY_FLAGS(); + CLEAR_COMPARE_FLAGS(); + CLEAR_CLIP1_FLAGS(); + CLEAR_ZERO_FLAGS(); + CLEAR_CLIP2_FLAGS(); + + UINT32 vce = 0; + for (int i = 0; i < 8; i++) + { + INT16 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)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(); +} + +static void cfunc_vch(void *param) +{ + ((rsp_cop2 *)param)->vch(); +} + + +// VCR +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100110 | +// ------------------------------------------------------ +// +// Vector clip reverse + +inline void rsp_cop2_simd::vcr() +{ + int op = m_op; + + CLEAR_CARRY_FLAGS(); + CLEAR_COMPARE_FLAGS(); + CLEAR_CLIP1_FLAGS(); + CLEAR_ZERO_FLAGS(); + CLEAR_CLIP2_FLAGS(); + + for (int i = 0; i < 8; i++) + { + INT16 s1, s2; + GET_VS1(s1, i); + GET_VS2(s2, i); + + if ((INT16)(s1 ^ s2) < 0) + { + if (s2 < 0) + { + SET_CLIP2_FLAG(i); + } + if ((s1 + s2) <= 0) + { + SET_ACCUM_L(~((UINT16)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(); +} + +static void cfunc_vcr(void *param) +{ + ((rsp_cop2 *)param)->vcr(); +} + + +// VMRG +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100111 | +// ------------------------------------------------------ +// +// Merges two vectors according to compare flags + +inline void rsp_cop2_simd::vmrg() +{ + int op = m_op; + + __m128i shuf = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); + __m128i s2mask = _mm_cmpeq_epi16(m_xvflag[COMPARE], _mm_setzero_si128()); + __m128i s1mask = _mm_xor_si128(s2mask, vec_neg1); + __m128i result = _mm_and_si128(m_xv[VS1REG], s1mask); + m_xv[VDREG] = _mm_or_si128(result, _mm_and_si128(shuf, s2mask)); + m_accum_l = m_xv[VDREG]; +} + +static void cfunc_vmrg(void *param) +{ + ((rsp_cop2 *)param)->vmrg(); +} + + +// VAND +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101000 | +// ------------------------------------------------------ +// +// Bitwise AND of two vector registers + +inline void rsp_cop2_simd::vand() +{ + int op = m_op; + + __m128i shuf = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); + m_accum_l = m_xv[VDREG] = _mm_and_si128(m_xv[VS1REG], shuf); +} + +static void cfunc_vand(void *param) +{ + ((rsp_cop2 *)param)->vand(); +} + + +// VNAND +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101001 | +// ------------------------------------------------------ +// +// Bitwise NOT AND of two vector registers + +inline void rsp_cop2_simd::vnand() +{ + int op = m_op; + + __m128i shuf = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); + m_accum_l = m_xv[VDREG] = _mm_xor_si128(_mm_and_si128(m_xv[VS1REG], shuf), vec_neg1); +} + +static void cfunc_vnand(void *param) +{ + ((rsp_cop2 *)param)->vnand(); +} + + +// VOR +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101010 | +// ------------------------------------------------------ +// +// Bitwise OR of two vector registers + +inline void rsp_cop2_simd::vor() +{ + int op = m_op; + + __m128i shuf = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); + m_accum_l = m_xv[VDREG] = _mm_or_si128(m_xv[VS1REG], shuf); +} + +static void cfunc_vor_simd(void *param) +{ + ((rsp_cop2 *)param)->vor(); +} + + +// VNOR +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101011 | +// ------------------------------------------------------ +// +// Bitwise NOT OR of two vector registers + +inline void rsp_cop2_simd::vnor() +{ + int op = m_op; + + __m128i shuf = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); + m_accum_l = m_xv[VDREG] = _mm_xor_si128(_mm_or_si128(m_xv[VS1REG], shuf), vec_neg1); +} + +static void cfunc_vnor(void *param) +{ + ((rsp_cop2 *)param)->vnor(); +} + + +// VXOR +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101100 | +// ------------------------------------------------------ +// +// Bitwise XOR of two vector registers + +inline void rsp_cop2_simd::vxor() +{ + int op = m_op; + + __m128i shuf = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); + m_accum_l = m_xv[VDREG] = _mm_xor_si128(m_xv[VS1REG], shuf); +} + +static void cfunc_vxor(void *param) +{ + ((rsp_cop2 *)param)->vxor(); +} + + +// VNXOR +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101101 | +// ------------------------------------------------------ +// +// Bitwise NOT XOR of two vector registers + +inline void rsp_cop2_simd::vnxor() +{ + int op = m_op; + + __m128i shuf = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); + m_accum_l = m_xv[VDREG] = _mm_xor_si128(_mm_xor_si128(m_xv[VS1REG], shuf), vec_neg1); +} + +static void cfunc_vnxor(void *param) +{ + ((rsp_cop2 *)param)->vnxor(); +} + + +// VRCP +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110000 | +// ------------------------------------------------------ +// +// Calculates reciprocal + +inline void rsp_cop2_simd::vrcp() +{ + int op = m_op; + + INT32 shifter = 0; + UINT16 urec; + INT32 rec; + EXTRACT16(m_xv[VS2REG], urec, EL); + rec = (INT16)urec; + INT32 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 address = ((datainput << shifter) & 0x7fc00000) >> 22; + INT32 fetchval = rsp_divtable[address]; + INT32 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; + + INSERT16(m_xv[VDREG], (UINT16)rec, VS1REG); + m_accum_l = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); +} + +static void cfunc_vrcp(void *param) +{ + ((rsp_cop2 *)param)->vrcp(); +} + + +// VRCPL +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110001 | +// ------------------------------------------------------ +// +// Calculates reciprocal low part + +inline void rsp_cop2_simd::vrcpl() +{ + int op = m_op; + +#if SIMUL_SIMD + m_old_reciprocal_res = m_reciprocal_res; + m_old_reciprocal_high = m_reciprocal_high; + m_old_dp_allowed = m_dp_allowed; +#endif + + INT32 shifter = 0; + + UINT16 urec; + EXTRACT16(m_xv[VS2REG], urec, EL); + INT32 rec = (INT16)urec; + INT32 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 address = ((datainput << shifter) & 0x7fc00000) >> 22; + INT32 fetchval = rsp_divtable[address]; + INT32 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; + + INSERT16(m_xv[VDREG], (UINT16)rec, VS1REG); + + for (int i = 0; i < 8; i++) + { + INT16 val; + EXTRACT16(m_xv[VS2REG], val, VEC_EL_2(EL, i)); + SET_ACCUM_L(val, i); + } +} + +static void cfunc_vrcpl(void *param) +{ + ((rsp_cop2 *)param)->vrcpl(); +} + + +// VRCPH +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110010 | +// ------------------------------------------------------ +// +// Calculates reciprocal high part + +inline void rsp_cop2_simd::vrcph() +{ + int op = m_op; + +#if SIMUL_SIMD + m_old_reciprocal_res = m_reciprocal_res; + m_old_reciprocal_high = m_reciprocal_high; + m_old_dp_allowed = m_dp_allowed; +#endif + + UINT16 rcph; + EXTRACT16(m_xv[VS2REG], rcph, EL); + m_reciprocal_high = rcph << 16; + m_dp_allowed = 1; + + m_accum_l = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); + + INSERT16(m_xv[VDREG], (INT16)(m_reciprocal_res >> 16), VS1REG); +} + +static void cfunc_vrcph(void *param) +{ + ((rsp_cop2 *)param)->vrcph(); +} + + +// VMOV +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110011 | +// ------------------------------------------------------ +// +// Moves element from vector to destination vector + +inline void rsp_cop2_simd::vmov() +{ + int op = m_op; + + INT16 val; + EXTRACT16(m_xv[VS2REG], val, EL); + INSERT16(m_xv[VDREG], val, VS1REG); + m_accum_l = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); +} + +static void cfunc_vmov(void *param) +{ + ((rsp_cop2 *)param)->vmov(); +} + + +// VRSQ +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110100 | +// ------------------------------------------------------ +// +// Calculates reciprocal square-root + +inline void rsp_cop2_simd::vrsq() +{ + int op = m_op; + + INT32 shifter = 0; + INT32 rec = (INT16)VREG_S(VS2REG, EL & 7); + INT32 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 address = ((datainput << shifter) & 0x7fc00000) >> 22; + address = ((address | 0x200) & 0x3fe) | (shifter & 1); + + INT32 fetchval = rsp_divtable[address]; + INT32 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)rec; + for (int i = 0; i < 8; i++) + { + SET_ACCUM_L(VREG_S(VS2REG, VEC_EL_2(EL, i)), i); + } +} + +static void cfunc_vrsq(void *param) +{ + ((rsp_cop2 *)param)->vrsq(); +} + + +// VRSQL +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110101 | +// ------------------------------------------------------ +// +// Calculates reciprocal square-root low part + +inline void rsp_cop2_simd::vrsql() +{ + int op = m_op; + +#if SIMUL_SIMD + m_old_reciprocal_res = m_reciprocal_res; + m_old_reciprocal_high = m_reciprocal_high; + m_old_dp_allowed = m_dp_allowed; +#endif + + INT32 shifter = 0; + UINT16 val; + EXTRACT16(m_xv[VS2REG], val, EL); + INT32 rec = (INT16)val; + INT32 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 address = ((datainput << shifter) & 0x7fc00000) >> 22; + address = ((address | 0x200) & 0x3fe) | (shifter & 1); + + INT32 fetchval = rsp_divtable[address]; + INT32 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; + + INSERT16(m_xv[VDREG], (UINT16)rec, VS1REG); + m_accum_l = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); +} + +static void cfunc_vrsql(void *param) +{ + ((rsp_cop2 *)param)->vrsql(); +} + + +// VRSQH +// +// 31 25 24 20 15 10 5 0 +// ------------------------------------------------------ +// | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110110 | +// ------------------------------------------------------ +// +// Calculates reciprocal square-root high part + +inline void rsp_cop2_simd::vrsqh() +{ + int op = m_op; + +#if SIMUL_SIMD + m_old_reciprocal_res = m_reciprocal_res; + m_old_reciprocal_high = m_reciprocal_high; + m_old_dp_allowed = m_dp_allowed; +#endif + + UINT16 val; + EXTRACT16(m_xv[VS2REG], val, EL); + m_reciprocal_high = val << 16; + m_dp_allowed = 1; + + m_accum_l = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); + + INSERT16(m_xv[VDREG], (INT16)(m_reciprocal_res >> 16), VS1REG); // store high part +} + +static void cfunc_vrsqh(void *param) +{ + ((rsp_cop2 *)param)->vrsqh(); +} + + +/*************************************************************************** + Vector Flag Reading/Writing +***************************************************************************/ + +inline void rsp_cop2_simd::mfc2() +{ + UINT32 op = m_op; + int el = (op >> 7) & 0xf; + + UINT16 out; + EXTRACT16(m_xv[VS1REG], out, (el >> 1)); + out >>= (1 - (el & 1)) * 8; + out &= 0x00ff; + + el++; + + UINT16 temp; + EXTRACT16(m_xv[VS1REG], temp, (el >> 1)); + temp >>= (1 - (el & 1)) * 8; + temp &= 0x00ff; + + m_rsp.m_rsp_state->r[RTREG] = (INT32)(INT16)((out << 8) | temp); +} + +static void cfunc_mfc2(void *param) +{ + ((rsp_cop2 *)param)->mfc2(); +} + + +inline void rsp_cop2_simd::cfc2() +{ + UINT32 op = m_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; + } + } +} + +static void cfunc_cfc2(void *param) +{ + ((rsp_cop2 *)param)->cfc2(); +} + + +inline void rsp_cop2_simd::mtc2() +{ + UINT32 op = m_op; + int el = (op >> 7) & 0xf; + INSERT16(m_xv[VS1REG], RTVAL, el >> 1); +} + +static void cfunc_mtc2(void *param) +{ + ((rsp_cop2 *)param)->mtc2(); +} + + +inline void rsp_cop2_simd::ctc2() +{ + UINT32 op = m_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; + } +} + +static void cfunc_ctc2(void *param) +{ + ((rsp_cop2 *)param)->ctc2(); +} + + +/*************************************************************************** + COP2 Opcode Compilation +***************************************************************************/ + +int rsp_cop2_simd::generate_cop2(drcuml_block *block, rsp_device::compiler_state *compiler, const opcode_desc *desc) +{ + UINT32 op = desc->opptr.l[0]; + UINT8 opswitch = RSREG; + + switch (opswitch) + { + case 0x00: /* MFCz */ + if (RTREG != 0) + { + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_mfc2, this); // callc mfc2 + } + return TRUE; + + case 0x02: /* CFCz */ + if (RTREG != 0) + { + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_cfc2, this); // callc cfc2 + } + return TRUE; + + case 0x04: /* MTCz */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, cfunc_mtc2, this); // callc mtc2 + return TRUE; + + case 0x06: /* CTCz */ + UML_MOV(block, mem(&m_op), desc->opptr.l[0]); // mov [arg0],desc->opptr.l + UML_CALLC(block, 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/emu/cpu/rsp/rspcp2s.h b/src/emu/cpu/rsp/rspcp2s.h new file mode 100644 index 00000000000..4c0e5d9a557 --- /dev/null +++ b/src/emu/cpu/rsp/rspcp2s.h @@ -0,0 +1,158 @@ +/*************************************************************************** + + rspcp2s.h + + Interface file for Reality Signal Processor (RSP) vector extensions + using SSSE3 SIMD acceleration. + + Copyright the MESS team + Released for general non-commercial use under the MAME license + Visit http://mamedev.org for licensing and usage restrictions. + +***************************************************************************/ + +#pragma once + +#ifndef __RSPCP2S_H__ +#define __RSPCP2S_H__ + +#include "cpu/drcuml.h" +#include "rsp.h" +#include "rspcp2.h" + +#include <tmmintrin.h> + +class rsp_cop2_simd : public rsp_cop2_drc +{ + friend class rsp_device; + + rsp_cop2_simd(rsp_device &rsp, running_machine &machine); + + virtual int generate_cop2(drcuml_block *block, rsp_device::compiler_state *compiler, const opcode_desc *desc); + virtual int generate_lwc2(drcuml_block *block, rsp_device::compiler_state *compiler, const opcode_desc *desc); + virtual int generate_swc2(drcuml_block *block, rsp_device::compiler_state *compiler, const opcode_desc *desc); + + virtual void state_string_export(const int index, astring &string); + +public: + 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(); + +#if SIMUL_SIMD + void backup_regs(); + void restore_regs(); + void verify_regs(); +#endif + +private: + virtual int generate_vector_opcode(drcuml_block *block, rsp_device::compiler_state *compiler, const opcode_desc *desc); + + UINT16 ACCUM_H(int x); + UINT16 ACCUM_M(int x); + UINT16 ACCUM_L(int x); + UINT16 ACCUM_LL(int x); + UINT16 CARRY_FLAG(const int x); + UINT16 COMPARE_FLAG(const int x); + UINT16 CLIP1_FLAG(const int x); + UINT16 ZERO_FLAG(const int x); + UINT16 CLIP2_FLAG(const int x); + UINT16 SATURATE_ACCUM(int accum, int slice, UINT16 negative, UINT16 positive); + + __m128i m_accum_h; + __m128i m_accum_m; + __m128i m_accum_l; + __m128i m_accum_ll; + + // Mirror of v[] for now, to be used in parallel as + // more vector ops are transitioned over + __m128i m_xv[32]; + __m128i m_xvflag[6]; + +#if SIMUL_SIMD + UINT32 m_old_r[35]; + UINT8 m_old_dmem[4096]; + + UINT32 m_scalar_r[35]; + UINT8 m_scalar_dmem[4096]; + + INT32 m_old_reciprocal_res; + UINT32 m_old_reciprocal_high; + INT32 m_old_dp_allowed; + + INT32 m_scalar_reciprocal_res; + UINT32 m_scalar_reciprocal_high; + INT32 m_scalar_dp_allowed; + + INT32 m_simd_reciprocal_res; + UINT32 m_simd_reciprocal_high; + INT32 m_simd_dp_allowed; +#endif +}; + +#endif /* __RSPCP2S_H__ */
\ No newline at end of file diff --git a/src/emu/cpu/rsp/rspdrc.c b/src/emu/cpu/rsp/rspdrc.c index 95d71ce48a5..fb999a809a7 100644 --- a/src/emu/cpu/rsp/rspdrc.c +++ b/src/emu/cpu/rsp/rspdrc.c @@ -25,6 +25,7 @@ #include "rsp.h" #include "rspdiv.h" #include "rspfe.h" +#include "rspcp2.h" #include "cpu/drcfe.h" #include "cpu/drcuml.h" #include "cpu/drcumlsh.h" @@ -52,213 +53,13 @@ extern offs_t rsp_dasm_one(char *buffer, offs_t pc, UINT32 op); /*************************************************************************** - MACROS + Macros ***************************************************************************/ #define R32(reg) m_regmap[reg] /*************************************************************************** - HELPFUL DEFINES -***************************************************************************/ - -#define VDREG ((op >> 6) & 0x1f) -#define VS1REG ((op >> 11) & 0x1f) -#define VS2REG ((op >> 16) & 0x1f) -#define EL ((op >> 21) & 0xf) - -#define SIMD_EXTRACT16(reg, value, element) \ - switch((element) & 7) \ - { \ - case 0: value = _mm_extract_epi16(reg, 0); break; \ - case 1: value = _mm_extract_epi16(reg, 1); break; \ - case 2: value = _mm_extract_epi16(reg, 2); break; \ - case 3: value = _mm_extract_epi16(reg, 3); break; \ - case 4: value = _mm_extract_epi16(reg, 4); break; \ - case 5: value = _mm_extract_epi16(reg, 5); break; \ - case 6: value = _mm_extract_epi16(reg, 6); break; \ - case 7: value = _mm_extract_epi16(reg, 7); break; \ - } - - -#define SIMD_INSERT16(reg, value, element) \ - switch((element) & 7) \ - { \ - case 0: reg = _mm_insert_epi16(reg, value, 0); break; \ - case 1: reg = _mm_insert_epi16(reg, value, 1); break; \ - case 2: reg = _mm_insert_epi16(reg, value, 2); break; \ - case 3: reg = _mm_insert_epi16(reg, value, 3); break; \ - case 4: reg = _mm_insert_epi16(reg, value, 4); break; \ - case 5: reg = _mm_insert_epi16(reg, value, 5); break; \ - case 6: reg = _mm_insert_epi16(reg, value, 6); break; \ - case 7: reg = _mm_insert_epi16(reg, value, 7); break; \ - } - - -#define SIMD_EXTRACT16C(reg, value, element) value = _mm_extract_epi16(reg, element); -#define SIMD_INSERT16C(reg, value, element) reg = _mm_insert_epi16(reg, value, element); - -#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)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 - - -#if USE_SIMD -static void cfunc_mfc2_simd(void *param); -static void cfunc_cfc2_simd(void *param); -static void cfunc_mtc2_simd(void *param); -static void cfunc_ctc2_simd(void *param); -#endif - -#if (!USE_SIMD || SIMUL_SIMD) -static void cfunc_mfc2_scalar(void *param); -static void cfunc_cfc2_scalar(void *param); -static void cfunc_mtc2_scalar(void *param); -static void cfunc_ctc2_scalar(void *param); -#endif - - -#if USE_SIMD -inline UINT16 rsp_device::VEC_ACCUM_H(int x) -{ - UINT16 out; - SIMD_EXTRACT16(m_accum_h, out, x); - return out; -} - -inline UINT16 rsp_device::VEC_ACCUM_M(int x) -{ - UINT16 out; - SIMD_EXTRACT16(m_accum_m, out, x); - return out; -} - -inline UINT16 rsp_device::VEC_ACCUM_L(int x) -{ - UINT16 out; - SIMD_EXTRACT16(m_accum_l, out, x); - return out; -} - -inline UINT16 rsp_device::VEC_ACCUM_LL(int x) -{ - UINT16 out; - SIMD_EXTRACT16(m_accum_ll, out, x); - return out; -} - -#define VEC_SET_ACCUM_H(v, x) SIMD_INSERT16(m_accum_h, v, x); -#define VEC_SET_ACCUM_M(v, x) SIMD_INSERT16(m_>accum_m, v, x); -#define VEC_SET_ACCUM_L(v, x) SIMD_INSERT16(m_accum_l, v, x); -#define VEC_SET_ACCUM_LL(v, x) SIMD_INSERT16(m_accum_ll, v, x); - -#define VEC_GET_SCALAR_VS1(out, i) SIMD_EXTRACT16(m_xv[VS1REG], out, i); -#define VEC_GET_SCALAR_VS2(out, i) SIMD_EXTRACT16(m_xv[VS2REG], out, VEC_EL_2(EL, i)); - -inline UINT16 rsp_device::VEC_CARRY_FLAG(const int x) -{ - UINT16 out; - SIMD_EXTRACT16(m_xvflag[CARRY], out, x); - return out; -} - -inline UINT16 rsp_device::VEC_COMPARE_FLAG(const int x) -{ - UINT16 out; - SIMD_EXTRACT16(m_xvflag[COMPARE], out, x); - return out; -} - -inline UINT16 rsp_device::VEC_CLIP1_FLAG(const int x) -{ - UINT16 out; - SIMD_EXTRACT16(m_xvflag[CLIP1], out, x); - return out; -} - -inline UINT16 rsp_device::VEC_ZERO_FLAG(const int x) -{ - UINT16 out; - SIMD_EXTRACT16(m_xvflag[ZERO], out, x); - return out; -} - -inline UINT16 rsp_device::VEC_CLIP2_FLAG(const int x) -{ - UINT16 out; - SIMD_EXTRACT16(m_xvflag[CLIP2], out, x); - return out; -} - -#define VEC_CLEAR_CARRY_FLAGS() { m_xvflag[CARRY] = _mm_setzero_si128(); } -#define VEC_CLEAR_COMPARE_FLAGS() { m_xvflag[COMPARE] = _mm_setzero_si128(); } -#define VEC_CLEAR_CLIP1_FLAGS() { m_xvflag[CLIP1] = _mm_setzero_si128(); } -#define VEC_CLEAR_ZERO_FLAGS() { m_xvflag[ZERO] = _mm_setzero_si128(); } -#define VEC_CLEAR_CLIP2_FLAGS() { m_xvflag[CLIP2] = _mm_setzero_si128(); } - -#define VEC_SET_CARRY_FLAG(x) { SIMD_INSERT16(m_xvflag[CARRY], 0xffff, x); } -#define VEC_SET_COMPARE_FLAG(x) { SIMD_INSERT16(m_xvflag[COMPARE], 0xffff, x); } -#define VEC_SET_CLIP1_FLAG(x) { SIMD_INSERT16(m_xvflag[CLIP1], 0xffff, x); } -#define VEC_SET_ZERO_FLAG(x) { SIMD_INSERT16(m_xvflag[ZERO], 0xffff, x); } -#define VEC_SET_CLIP2_FLAG(x) { SIMD_INSERT16(m_xvflag[CLIP2], 0xffff, x); } - -#define VEC_CLEAR_CARRY_FLAG(x) { SIMD_INSERT16(m_xvflag[CARRY], 0, x); } -#define VEC_CLEAR_COMPARE_FLAG(x) { SIMD_INSERT16(m_xvflag[COMPARE], 0, x); } -#define VEC_CLEAR_CLIP1_FLAG(x) { SIMD_INSERT16(m_xvflag[CLIP1], 0, x); } -#define VEC_CLEAR_ZERO_FLAG(x) { SIMD_INSERT16(m_xvflag[ZERO], 0, x); } -#define VEC_CLEAR_CLIP2_FLAG(x) { SIMD_INSERT16(m_xvflag[CLIP2], 0, x); } - -#endif - -#define ACCUM_H(x) (UINT16)m_accum[x].w[3] -#define ACCUM_M(x) (UINT16)m_accum[x].w[2] -#define ACCUM_L(x) (UINT16)m_accum[x].w[1] -#define ACCUM_LL(x) (UINT16)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 SCALAR_GET_VS1(out, i) out = VREG_S(VS1REG, i) -#define SCALAR_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; } - - -/*************************************************************************** - INLINE FUNCTIONS + Inline Functions ***************************************************************************/ /*------------------------------------------------- @@ -331,9 +132,10 @@ void rsp_device::rspdrc_add_dmem(UINT32 *base) m_dmem8 = (UINT8*)base; } -inline UINT8 rsp_device::DM_READ8(UINT32 address) +UINT8 rsp_device::DM_READ8(UINT32 address) { UINT8 ret = m_dmem8[BYTE4_XOR_BE(address & 0xfff)]; + //printf("R8:%08x=%02x\n", address, ret); return ret; } @@ -347,12 +149,13 @@ static void cfunc_read8(void *param) ((rsp_device *)param)->ccfunc_read8(); } -inline UINT16 rsp_device::DM_READ16(UINT32 address) +UINT16 rsp_device::DM_READ16(UINT32 address) { UINT16 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; } @@ -366,7 +169,7 @@ static void cfunc_read16(void *param) ((rsp_device *)param)->ccfunc_read16(); } -inline UINT32 rsp_device::DM_READ32(UINT32 address) +UINT32 rsp_device::DM_READ32(UINT32 address) { UINT32 ret; address &= 0xfff; @@ -374,6 +177,7 @@ inline UINT32 rsp_device::DM_READ32(UINT32 address) 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; } @@ -387,10 +191,11 @@ static void cfunc_read32(void *param) ((rsp_device *)param)->ccfunc_read32();; } -inline void rsp_device::DM_WRITE8(UINT32 address, UINT8 data) +void rsp_device::DM_WRITE8(UINT32 address, UINT8 data) { address &= 0xfff; m_dmem8[BYTE4_XOR_BE(address)] = data; + //printf("W8:%08x=%02x\n", address, data); } inline void rsp_device::ccfunc_write8() @@ -403,11 +208,12 @@ static void cfunc_write8(void *param) ((rsp_device *)param)->ccfunc_write8();; } -inline void rsp_device::DM_WRITE16(UINT32 address, UINT16 data) +void rsp_device::DM_WRITE16(UINT32 address, UINT16 data) { 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); } inline void rsp_device::ccfunc_write16() @@ -420,13 +226,14 @@ static void cfunc_write16(void *param) ((rsp_device *)param)->ccfunc_write16();; } -inline void rsp_device::DM_WRITE32(UINT32 address, UINT32 data) +void rsp_device::DM_WRITE32(UINT32 address, UINT32 data) { 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); } inline void rsp_device::ccfunc_write32() @@ -452,52 +259,6 @@ void rsp_device::rspdrc_set_options(UINT32 options) } -/*------------------------------------------------- - cfunc_printf_debug - generic printf for - debugging --------------------------------------------------*/ - -#ifdef UNUSED_CODE -inline void rs_device::cfunc_printf_debug() -{ - switch(m_arg2) - { - case 0: // WRITE8 - printf("%04x:%02x\n", m_rsp_state->arg0 & 0xffff, (UINT8)m_rsp_state->arg1); - break; - case 1: // WRITE16 - printf("%04x:%04x\n", m_rsp_state->arg0 & 0xffff, (UINT16)m_rsp_state->arg1); - break; - case 2: // WRITE32 - printf("%04x:%08x\n", m_rsp_state->arg0 & 0xffff, m_rsp_state->arg1); - break; - case 3: // READ8 - printf("%04xr%02x\n", m_rsp_state->arg0 & 0xffff, (UINT8)m_rsp_state->arg1); - break; - case 4: // READ16 - printf("%04xr%04x\n", m_rsp_state->arg0 & 0xffff, (UINT16)m_rsp_state->arg1); - break; - case 5: // READ32 - printf("%04xr%08x\n", m_rsp_state->arg0 & 0xffff, m_rsp_state->arg1); - break; - case 6: // Checksum - printf("Sum: %08x\n", m_rsp_state->arg0); - break; - case 7: // Checksum - printf("Correct Sum: %08x\n", m_rsp_state->arg0); - break; - default: // ??? - printf("%08x %08x\n", m_rsp_state->arg0 & 0xffff, m_rsp_state->arg1); - break; - } -} - -static void cfunc_printf_debug(void *param) -{ - ((rsp_device *)param)->ccfunc_printf_debug(); -} -#endif - inline void rsp_device::ccfunc_get_cop0_reg() { int reg = m_rsp_state->arg0; @@ -552,6451 +313,12 @@ static void cfunc_set_cop0_reg(void *param) ((rsp_device *)param)->ccfunc_set_cop0_reg(); } -inline void rsp_device::ccfunc_unimplemented_opcode() -{ - int op = m_rsp_state->arg0; - if ((machine().debug_flags & DEBUG_FLAG_ENABLED) != 0) - { - char string[200]; - rsp_dasm_one(string, m_ppc, op); - osd_printf_debug("%08X: %s\n", m_ppc, string); - } - - fatalerror("RSP: unknown opcode %02X (%08X) at %08X\n", op >> 26, op, m_ppc); -} - -static void cfunc_unimplemented_opcode(void *param) -{ - ((rsp_device *)param)->ccfunc_unimplemented_opcode(); -} - /*****************************************************************************/ -/* Legacy. Going forward, this will be transitioned into unrolled opcode decodes. */ -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 -}; - -#if USE_SIMD -static __m128i vec_himask; -static __m128i vec_lomask; -static __m128i vec_hibit; -static __m128i vec_lobit; -static __m128i vec_n32768; -static __m128i vec_32767; -static __m128i vec_flagmask; -static __m128i vec_shiftmask2; -static __m128i vec_shiftmask4; -static __m128i vec_flag_reverse; -static __m128i vec_neg1; -static __m128i vec_zero; -static __m128i vec_shuf[16]; -static __m128i vec_shuf_inverse[16]; -#endif - void rsp_device::rspcom_init() { -#if USE_SIMD - VEC_CLEAR_CARRY_FLAGS(); - VEC_CLEAR_COMPARE_FLAGS(); - VEC_CLEAR_CLIP1_FLAGS(); - VEC_CLEAR_ZERO_FLAGS(); - VEC_CLEAR_CLIP2_FLAGS(); -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - CLEAR_CARRY_FLAGS(); - CLEAR_COMPARE_FLAGS(); - CLEAR_CLIP1_FLAGS(); - CLEAR_ZERO_FLAGS(); - CLEAR_CLIP2_FLAGS(); -#endif - -#if USE_SIMD - vec_shuf_inverse[ 0] = _mm_set_epi16(0x0f0e, 0x0d0c, 0x0b0a, 0x0908, 0x0706, 0x0504, 0x0302, 0x0100); // none - vec_shuf_inverse[ 1] = _mm_set_epi16(0x0f0e, 0x0d0c, 0x0b0a, 0x0908, 0x0706, 0x0504, 0x0302, 0x0100); // ??? - vec_shuf_inverse[ 2] = _mm_set_epi16(0x0d0c, 0x0d0c, 0x0908, 0x0908, 0x0504, 0x0504, 0x0100, 0x0100); // 0q - vec_shuf_inverse[ 3] = _mm_set_epi16(0x0f0e, 0x0f0e, 0x0b0a, 0x0b0a, 0x0706, 0x0706, 0x0302, 0x0302); // 1q - vec_shuf_inverse[ 4] = _mm_set_epi16(0x0908, 0x0908, 0x0908, 0x0908, 0x0100, 0x0100, 0x0100, 0x0100); // 0h - vec_shuf_inverse[ 5] = _mm_set_epi16(0x0b0a, 0x0b0a, 0x0b0a, 0x0b0a, 0x0302, 0x0302, 0x0302, 0x0302); // 1h - vec_shuf_inverse[ 6] = _mm_set_epi16(0x0d0c, 0x0d0c, 0x0d0c, 0x0d0c, 0x0504, 0x0504, 0x0504, 0x0504); // 2h - vec_shuf_inverse[ 7] = _mm_set_epi16(0x0f0e, 0x0f0e, 0x0f0e, 0x0f0e, 0x0706, 0x0706, 0x0706, 0x0706); // 3h - vec_shuf_inverse[ 8] = _mm_set_epi16(0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100); // 0 - vec_shuf_inverse[ 9] = _mm_set_epi16(0x0302, 0x0302, 0x0302, 0x0302, 0x0302, 0x0302, 0x0302, 0x0302); // 1 - vec_shuf_inverse[10] = _mm_set_epi16(0x0504, 0x0504, 0x0504, 0x0504, 0x0504, 0x0504, 0x0504, 0x0504); // 2 - vec_shuf_inverse[11] = _mm_set_epi16(0x0706, 0x0706, 0x0706, 0x0706, 0x0706, 0x0706, 0x0706, 0x0706); // 3 - vec_shuf_inverse[12] = _mm_set_epi16(0x0908, 0x0908, 0x0908, 0x0908, 0x0908, 0x0908, 0x0908, 0x0908); // 4 - vec_shuf_inverse[13] = _mm_set_epi16(0x0b0a, 0x0b0a, 0x0b0a, 0x0b0a, 0x0b0a, 0x0b0a, 0x0b0a, 0x0b0a); // 5 - vec_shuf_inverse[14] = _mm_set_epi16(0x0d0c, 0x0d0c, 0x0d0c, 0x0d0c, 0x0d0c, 0x0d0c, 0x0d0c, 0x0d0c); // 6 - vec_shuf_inverse[15] = _mm_set_epi16(0x0f0e, 0x0f0e, 0x0f0e, 0x0f0e, 0x0f0e, 0x0f0e, 0x0f0e, 0x0f0e); // 7 - - vec_shuf[ 0] = _mm_set_epi16(0x0100, 0x0302, 0x0504, 0x0706, 0x0908, 0x0b0a, 0x0d0c, 0x0f0e); // none - vec_shuf[ 1] = _mm_set_epi16(0x0100, 0x0302, 0x0504, 0x0706, 0x0908, 0x0b0a, 0x0d0c, 0x0f0e); // ??? - vec_shuf[ 2] = _mm_set_epi16(0x0302, 0x0302, 0x0706, 0x0706, 0x0b0a, 0x0b0a, 0x0f0e, 0x0f0e); // 0q - vec_shuf[ 3] = _mm_set_epi16(0x0100, 0x0100, 0x0504, 0x0706, 0x0908, 0x0908, 0x0d0c, 0x0d0c); // 1q - vec_shuf[ 4] = _mm_set_epi16(0x0706, 0x0706, 0x0706, 0x0706, 0x0f0e, 0x0f0e, 0x0f0e, 0x0f0e); // 0q - vec_shuf[ 5] = _mm_set_epi16(0x0504, 0x0504, 0x0504, 0x0504, 0x0d0c, 0x0d0c, 0x0d0c, 0x0d0c); // 1q - vec_shuf[ 6] = _mm_set_epi16(0x0302, 0x0302, 0x0302, 0x0302, 0x0b0a, 0x0b0a, 0x0b0a, 0x0b0a); // 2q - vec_shuf[ 7] = _mm_set_epi16(0x0100, 0x0100, 0x0100, 0x0100, 0x0908, 0x0908, 0x0908, 0x0908); // 3q - vec_shuf[ 8] = _mm_set_epi16(0x0f0e, 0x0f0e, 0x0f0e, 0x0f0e, 0x0f0e, 0x0f0e, 0x0f0e, 0x0f0e); // 0 - vec_shuf[ 9] = _mm_set_epi16(0x0d0c, 0x0d0c, 0x0d0c, 0x0d0c, 0x0d0c, 0x0d0c, 0x0d0c, 0x0d0c); // 1 - vec_shuf[10] = _mm_set_epi16(0x0b0a, 0x0b0a, 0x0b0a, 0x0b0a, 0x0b0a, 0x0b0a, 0x0b0a, 0x0b0a); // 2 - vec_shuf[11] = _mm_set_epi16(0x0908, 0x0908, 0x0908, 0x0908, 0x0908, 0x0908, 0x0908, 0x0908); // 3 - vec_shuf[12] = _mm_set_epi16(0x0706, 0x0706, 0x0706, 0x0706, 0x0706, 0x0706, 0x0706, 0x0706); // 4 - vec_shuf[13] = _mm_set_epi16(0x0504, 0x0504, 0x0504, 0x0504, 0x0504, 0x0504, 0x0504, 0x0504); // 5 - vec_shuf[14] = _mm_set_epi16(0x0302, 0x0302, 0x0302, 0x0302, 0x0302, 0x0302, 0x0302, 0x0302); // 6 - vec_shuf[15] = _mm_set_epi16(0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100); // 7 - m_accum_h = _mm_setzero_si128(); - m_accum_m = _mm_setzero_si128(); - m_accum_l = _mm_setzero_si128(); - m_accum_ll = _mm_setzero_si128(); - vec_neg1 = _mm_set_epi64x(0xffffffffffffffffL, 0xffffffffffffffffL); - vec_zero = _mm_setzero_si128(); - vec_himask = _mm_set_epi64x(0xffff0000ffff0000L, 0xffff0000ffff0000L); - vec_lomask = _mm_set_epi64x(0x0000ffff0000ffffL, 0x0000ffff0000ffffL); - vec_hibit = _mm_set_epi64x(0x0001000000010000L, 0x0001000000010000L); - vec_lobit = _mm_set_epi64x(0x0000000100000001L, 0x0000000100000001L); - vec_32767 = _mm_set_epi64x(0x7fff7fff7fff7fffL, 0x7fff7fff7fff7fffL); - vec_n32768 = _mm_set_epi64x(0x8000800080008000L, 0x8000800080008000L); - vec_flagmask = _mm_set_epi64x(0x0001000100010001L, 0x0001000100010001L); - vec_shiftmask2 = _mm_set_epi64x(0x0000000300000003L, 0x0000000300000003L); - vec_shiftmask4 = _mm_set_epi64x(0x000000000000000fL, 0x000000000000000fL); - vec_flag_reverse = _mm_set_epi16(0x0100, 0x0302, 0x0504, 0x0706, 0x0908, 0x0b0a, 0x0d0c, 0x0f0e); -#endif -} - - -#if USE_SIMD -// LBV -// -// 31 25 20 15 10 6 0 -// -------------------------------------------------- -// | 110010 | BBBBB | TTTTT | 00000 | IIII | Offset | -// -------------------------------------------------- -// -// Load 1 byte to vector byte index - -inline void rsp_device::ccfunc_rsp_lbv_simd() -{ - UINT32 op = m_rsp_state->arg0; - - UINT32 ea = 0; - 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_state->r[base] + offset : offset; - - UINT16 element; - SIMD_EXTRACT16(m_xv[dest], element, (index >> 1)); - element &= 0xff00 >> ((1-(index & 1)) * 8); - element |= DM_READ8(ea) << ((1-(index & 1)) * 8); - SIMD_INSERT16(m_xv[dest], element, (index >> 1)); -} - -static void cfunc_rsp_lbv_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_lbv_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) -inline void rsp_device::ccfunc_rsp_lbv_scalar() -{ - UINT32 op = m_rsp_state->arg0; - - UINT32 ea = 0; - 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_state->r[base] + offset : offset; - VREG_B(dest, index) = DM_READ8(ea); -} - -static void cfunc_rsp_lbv_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_lbv_scalar(); -} -#endif - -#if USE_SIMD -// LSV -// -// 31 25 20 15 10 6 0 -// -------------------------------------------------- -// | 110010 | BBBBB | TTTTT | 00001 | IIII | Offset | -// -------------------------------------------------- -// -// Loads 2 bytes starting from vector byte index - -inline void rsp_device::ccfunc_rsp_lsv_simd() -{ - UINT32 op = m_rsp_state->arg0; - int dest = (op >> 16) & 0x1f; - int base = (op >> 21) & 0x1f; - int index = (op >> 7) & 0xe; - int offset = (op & 0x7f); - if (offset & 0x40) - { - offset |= 0xffffffc0; - } - - UINT32 ea = (base) ? m_rsp_state->r[base] + (offset * 2) : (offset * 2); - int end = index + 2; - for (int i = index; i < end; i++) - { - UINT16 element; - SIMD_EXTRACT16(m_xv[dest], element, (i >> 1)); - element &= 0xff00 >> ((1 - (i & 1)) * 8); - element |= DM_READ8(ea) << ((1 - (i & 1)) * 8); - SIMD_INSERT16(m_xv[dest], element, (i >> 1)); - ea++; - } -} - -static void cfunc_rsp_lsv_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_lsv_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) -inline void rsp_device::ccfunc_rsp_lsv_scalar() -{ - UINT32 op = m_rsp_state->arg0; - int dest = (op >> 16) & 0x1f; - int base = (op >> 21) & 0x1f; - int index = (op >> 7) & 0xe; - int offset = (op & 0x7f); - if (offset & 0x40) - { - offset |= 0xffffffc0; - } - - UINT32 ea = (base) ? m_rsp_state->r[base] + (offset * 2) : (offset * 2); - int end = index + 2; - for (int i = index; i < end; i++) - { - VREG_B(dest, i) = DM_READ8(ea); - ea++; - } -} - -static void cfunc_rsp_lsv_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_lsv_scalar(); -} -#endif - -#if USE_SIMD -// LLV -// -// 31 25 20 15 10 6 0 -// -------------------------------------------------- -// | 110010 | BBBBB | TTTTT | 00010 | IIII | Offset | -// -------------------------------------------------- -// -// Loads 4 bytes starting from vector byte index - -inline void rsp_device::ccfunc_rsp_llv_simd() -{ - UINT32 op = m_rsp_state->arg0; - UINT32 ea = 0; - int dest = (op >> 16) & 0x1f; - int base = (op >> 21) & 0x1f; - int index = (op >> 7) & 0xc; - int offset = (op & 0x7f); - if (offset & 0x40) - { - offset |= 0xffffffc0; - } - - ea = (base) ? m_rsp_state->r[base] + (offset * 4) : (offset * 4); - - int end = index + 4; - - for (int i = index; i < end; i++) - { - UINT16 element; - SIMD_EXTRACT16(m_xv[dest], element, (i >> 1)); - element &= 0xff00 >> ((1 - (i & 1)) * 8); - element |= DM_READ8(ea) << ((1 - (i & 1)) * 8); - SIMD_INSERT16(m_xv[dest], element, (i >> 1)); - ea++; - } -} - -static void cfunc_rsp_llv_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_llv_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_llv_scalar() -{ - UINT32 op = m_rsp_state->arg0; - UINT32 ea = 0; - int dest = (op >> 16) & 0x1f; - int base = (op >> 21) & 0x1f; - int index = (op >> 7) & 0xc; - int offset = (op & 0x7f); - if (offset & 0x40) - { - offset |= 0xffffffc0; - } - - ea = (base) ? m_rsp_state->r[base] + (offset * 4) : (offset * 4); - - int end = index + 4; - - for (int i = index; i < end; i++) - { - VREG_B(dest, i) = DM_READ8(ea); - ea++; - } -} - -static void cfunc_rsp_llv_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_llv_scalar(); -} -#endif - -#if USE_SIMD -// LDV -// -// 31 25 20 15 10 6 0 -// -------------------------------------------------- -// | 110010 | BBBBB | TTTTT | 00011 | IIII | Offset | -// -------------------------------------------------- -// -// Loads 8 bytes starting from vector byte index - -inline void rsp_device::ccfunc_rsp_ldv_simd() -{ - UINT32 op = m_rsp_state->arg0; - UINT32 ea = 0; - int dest = (op >> 16) & 0x1f; - int base = (op >> 21) & 0x1f; - int index = (op >> 7) & 0x8; - int offset = (op & 0x7f); - if (offset & 0x40) - { - offset |= 0xffffffc0; - } - - ea = (base) ? m_rsp_state->r[base] + (offset * 8) : (offset * 8); - - int end = index + 8; - - for (int i = index; i < end; i++) - { - UINT16 element; - SIMD_EXTRACT16(m_xv[dest], element, (i >> 1)); - element &= 0xff00 >> ((1 - (i & 1)) * 8); - element |= DM_READ8(ea) << ((1 - (i & 1)) * 8); - SIMD_INSERT16(m_xv[dest], element, (i >> 1)); - ea++; - } -} - -static void cfunc_rsp_ldv_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_ldv_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_ldv_scalar() -{ - UINT32 op = m_rsp_state->arg0; - UINT32 ea = 0; - int dest = (op >> 16) & 0x1f; - int base = (op >> 21) & 0x1f; - int index = (op >> 7) & 0x8; - int offset = (op & 0x7f); - if (offset & 0x40) - { - offset |= 0xffffffc0; - } - - ea = (base) ? m_rsp_state->r[base] + (offset * 8) : (offset * 8); - - int end = index + 8; - - for (int i = index; i < end; i++) - { - VREG_B(dest, i) = DM_READ8(ea); - ea++; - } -} - -static void cfunc_rsp_ldv_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_ldv_scalar(); -} -#endif - -#if USE_SIMD -// LQV -// -// 31 25 20 15 10 6 0 -// -------------------------------------------------- -// | 110010 | BBBBB | TTTTT | 00100 | IIII | Offset | -// -------------------------------------------------- -// -// Loads up to 16 bytes starting from vector byte index - -inline void rsp_device::ccfunc_rsp_lqv_simd() -{ - UINT32 op = m_rsp_state->arg0; - int dest = (op >> 16) & 0x1f; - int base = (op >> 21) & 0x1f; - int offset = (op & 0x7f); - if (offset & 0x40) - { - offset |= 0xffffffc0; - } - - UINT32 ea = (base) ? 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++) - { - UINT16 element; - SIMD_EXTRACT16(m_xv[dest], element, (i >> 1)); - element &= 0xff00 >> ((1 - (i & 1)) * 8); - element |= DM_READ8(ea) << ((1 - (i & 1)) * 8); - SIMD_INSERT16(m_xv[dest], element, (i >> 1)); - ea++; - } -} - -static void cfunc_rsp_lqv_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_lqv_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_lqv_scalar() -{ - UINT32 op = m_rsp_state->arg0; - int dest = (op >> 16) & 0x1f; - int base = (op >> 21) & 0x1f; - int offset = (op & 0x7f); - if (offset & 0x40) - { - offset |= 0xffffffc0; - } - - UINT32 ea = (base) ? 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) = DM_READ8(ea); - ea++; - } -} - -static void cfunc_rsp_lqv_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_lqv_scalar(); -} -#endif - -#if USE_SIMD -// 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 - -inline void rsp_device::ccfunc_rsp_lrv_simd() -{ - UINT32 op = m_rsp_state->arg0; - 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 ea = (base) ? m_rsp_state->r[base] + (offset * 16) : (offset * 16); - - index = 16 - ((ea & 0xf) - index); - ea &= ~0xf; - - for (int i = index; i < 16; i++) - { - UINT16 element; - SIMD_EXTRACT16(m_xv[dest], element, (i >> 1)); - element &= 0xff00 >> ((1-(i & 1)) * 8); - element |= DM_READ8(ea) << ((1-(i & 1)) * 8); - SIMD_INSERT16(m_xv[dest], element, (i >> 1)); - ea++; - } -} - -static void cfunc_rsp_lrv_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_lrv_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_lrv_scalar() -{ - UINT32 op = m_rsp_state->arg0; - 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 ea = (base) ? 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) = DM_READ8(ea); - ea++; - } -} - -static void cfunc_rsp_lrv_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_lrv_scalar(); -} -#endif - -#if USE_SIMD -// 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 - -inline void rsp_device::ccfunc_rsp_lpv_simd() -{ - UINT32 op = m_rsp_state->arg0; - 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 ea = (base) ? m_rsp_state->r[base] + (offset * 8) : (offset * 8); - - for (int i = 0; i < 8; i++) - { - SIMD_INSERT16(m_xv[dest], DM_READ8(ea + (((16-index) + i) & 0xf)) << 8, i); - } -} - -static void cfunc_rsp_lpv_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_lpv_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_lpv_scalar() -{ - UINT32 op = m_rsp_state->arg0; - 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 ea = (base) ? m_rsp_state->r[base] + (offset * 8) : (offset * 8); - - for (int i = 0; i < 8; i++) - { - W_VREG_S(dest, i) = DM_READ8(ea + (((16-index) + i) & 0xf)) << 8; - } -} - -static void cfunc_rsp_lpv_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_lpv_scalar(); -} -#endif - -#if USE_SIMD -// 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 - -inline void rsp_device::ccfunc_rsp_luv_simd() -{ - UINT32 op = m_rsp_state->arg0; - 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 ea = (base) ? m_rsp_state->r[base] + (offset * 8) : (offset * 8); - - for (int i = 0; i < 8; i++) - { - SIMD_INSERT16(m_xv[dest], DM_READ8(ea + (((16-index) + i) & 0xf)) << 7, i); - } -} - -static void cfunc_rsp_luv_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_luv_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_luv_scalar() -{ - UINT32 op = m_rsp_state->arg0; - 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 ea = (base) ? m_rsp_state->r[base] + (offset * 8) : (offset * 8); - - for (int i = 0; i < 8; i++) - { - W_VREG_S(dest, i) = DM_READ8(ea + (((16-index) + i) & 0xf)) << 7; - } -} - -static void cfunc_rsp_luv_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_luv_scalar(); -} -#endif - -#if USE_SIMD -// 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 - -inline void rsp_device::ccfunc_rsp_lhv_simd() -{ - UINT32 op = m_rsp_state->arg0; - 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 ea = (base) ? m_rsp_state->r[base] + (offset * 16) : (offset * 16); - - for (int i = 0; i < 8; i++) - { - SIMD_INSERT16(m_xv[dest], DM_READ8(ea + (((16-index) + (i<<1)) & 0xf)) << 7, i); - } -} - -static void cfunc_rsp_lhv_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_lhv_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_lhv_scalar() -{ - UINT32 op = m_rsp_state->arg0; - 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 ea = (base) ? m_rsp_state->r[base] + (offset * 16) : (offset * 16); - - for (int i = 0; i < 8; i++) - { - W_VREG_S(dest, i) = DM_READ8(ea + (((16-index) + (i<<1)) & 0xf)) << 7; - } -} - -static void cfunc_rsp_lhv_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_lhv_scalar(); -} -#endif - -#if USE_SIMD -// 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 - -inline void rsp_device::ccfunc_rsp_lfv_simd() -{ - UINT32 op = m_rsp_state->arg0; - 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 ea = (base) ? 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++) - { - SIMD_INSERT16(m_xv[dest], DM_READ8(ea) << 7, i); - ea += 4; - } -} - -static void cfunc_rsp_lfv_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_lfv_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_lfv_scalar() -{ - UINT32 op = m_rsp_state->arg0; - 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 ea = (base) ? 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) = DM_READ8(ea) << 7; - ea += 4; - } -} - -static void cfunc_rsp_lfv_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_lfv_scalar(); -} -#endif - -#if USE_SIMD -// 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 - -inline void rsp_device::ccfunc_rsp_lwv_simd() -{ - UINT32 op = m_rsp_state->arg0; - 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 ea = (base) ? m_rsp_state->r[base] + (offset * 16) : (offset * 16); - int end = (16 - index) + 16; - - UINT8 val[16]; - for (int i = (16 - index); i < end; i++) - { - val[i & 0xf] = DM_READ8(ea); - ea += 4; - } - - m_xv[dest] = _mm_set_epi8(val[15], val[14], val[13], val[12], val[11], val[10], val[ 9], val[ 8], - val[ 7], val[ 6], val[ 5], val[ 4], val[ 3], val[ 2], val[ 1], val[ 0]); -} - -static void cfunc_rsp_lwv_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_lwv_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_lwv_scalar() -{ - UINT32 op = m_rsp_state->arg0; - 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 ea = (base) ? 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) = DM_READ8(ea); - ea += 4; - } -} - -static void cfunc_rsp_lwv_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_lwv_scalar(); -} -#endif - -#if USE_SIMD -// 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 - -inline void rsp_device::ccfunc_rsp_ltv_simd() -{ - UINT32 op = m_rsp_state->arg0; - 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 = 7 - (index >> 1); - - UINT32 ea = (base) ? 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; - UINT16 value = (DM_READ8(ea) << 8) | DM_READ8(ea + 1); - SIMD_INSERT16(m_xv[i], value, (element >> 1)); - ea += 2; - } -} - -static void cfunc_rsp_ltv_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_ltv_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_ltv_scalar() -{ - UINT32 op = m_rsp_state->arg0; - 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 = 7 - (index >> 1); - - UINT32 ea = (base) ? 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)) = DM_READ8(ea); - VREG_B(i, ((element + 1) & 0xf)) = DM_READ8(ea + 1); - ea += 2; - } -} - -static void cfunc_rsp_ltv_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_ltv_scalar(); -} -#endif - -#if USE_SIMD && SIMUL_SIMD -inline void rsp_device::ccfunc_backup_regs() -{ - memcpy(m_old_dmem, m_dmem8, sizeof(m_old_dmem)); - memcpy(m_old_r, m_r, sizeof(m_r)); - - m_simd_reciprocal_res = m_reciprocal_res; - m_simd_reciprocal_high = m_reciprocal_high; - m_simd_dp_allowed = m_dp_allowed; - - m_reciprocal_res = m_old_reciprocal_res; - m_reciprocal_high = m_old_reciprocal_high; - m_dp_allowed = m_old_dp_allowed; -} - -static void cfunc_backup_regs(void *param) -{ - ((rsp_device *)param)->ccfunc_backup_regs(); -} - -inline void rsp_device::ccfunc_restore_regs() -{ - memcpy(m_scalar_r, m_r, sizeof(m_r)); - memcpy(m_r, m_old_r, sizeof(m_r)); - memcpy(m_scalar_dmem, m_dmem8, sizeof(m_scalar_dmem)); - memcpy(m_dmem8, m_old_dmem, sizeof(m_old_dmem)); - - m_scalar_reciprocal_res = m_reciprocal_res; - m_scalar_reciprocal_high = m_reciprocal_high; - m_scalar_dp_allowed = m_dp_allowed; - - m_reciprocal_res = m_simd_reciprocal_res; - m_reciprocal_high = m_simd_reciprocal_high; - m_dp_allowed = m_simd_dp_allowed; -} - -static void cfunc_restore_regs(void *param) -{ - ((rsp_device *)param)->ccfunc_restore_regs(); -} - -inline void rsp_device::ccfunc_verify_regs() -{ - int op = m_rsp_state->arg0; - if (VEC_ACCUM_H(0) != ACCUM_H(0)) fatalerror("ACCUM_H element 0 mismatch (SIMD %04x vs. Scalar %04x) after op: %08x\n", VEC_ACCUM_H(0), ACCUM_H(0), op); - if (VEC_ACCUM_H(1) != ACCUM_H(1)) fatalerror("ACCUM_H element 1 mismatch (SIMD %04x vs. Scalar %04x) after op: %08x\n", VEC_ACCUM_H(1), ACCUM_H(1), op); - if (VEC_ACCUM_H(2) != ACCUM_H(2)) fatalerror("ACCUM_H element 2 mismatch (SIMD %04x vs. Scalar %04x) after op: %08x\n", VEC_ACCUM_H(2), ACCUM_H(2), op); - if (VEC_ACCUM_H(3) != ACCUM_H(3)) fatalerror("ACCUM_H element 3 mismatch (SIMD %04x vs. Scalar %04x) after op: %08x\n", VEC_ACCUM_H(3), ACCUM_H(3), op); - if (VEC_ACCUM_H(4) != ACCUM_H(4)) fatalerror("ACCUM_H element 4 mismatch (SIMD %04x vs. Scalar %04x) after op: %08x\n", VEC_ACCUM_H(4), ACCUM_H(4), op); - if (VEC_ACCUM_H(5) != ACCUM_H(5)) fatalerror("ACCUM_H element 5 mismatch (SIMD %04x vs. Scalar %04x) after op: %08x\n", VEC_ACCUM_H(5), ACCUM_H(5), op); - if (VEC_ACCUM_H(6) != ACCUM_H(6)) fatalerror("ACCUM_H element 6 mismatch (SIMD %04x vs. Scalar %04x) after op: %08x\n", VEC_ACCUM_H(6), ACCUM_H(6), op); - if (VEC_ACCUM_H(7) != ACCUM_H(7)) fatalerror("ACCUM_H element 7 mismatch (SIMD %04x vs. Scalar %04x) after op: %08x\n", VEC_ACCUM_H(7), ACCUM_H(7), op); - if (VEC_ACCUM_M(0) != ACCUM_M(0)) fatalerror("ACCUM_M element 0 mismatch (SIMD %04x vs. Scalar %04x) after op: %08x\n", VEC_ACCUM_M(0), ACCUM_M(0), op); - if (VEC_ACCUM_M(1) != ACCUM_M(1)) fatalerror("ACCUM_M element 1 mismatch (SIMD %04x vs. Scalar %04x) after op: %08x\n", VEC_ACCUM_M(1), ACCUM_M(1), op); - if (VEC_ACCUM_M(2) != ACCUM_M(2)) fatalerror("ACCUM_M element 2 mismatch (SIMD %04x vs. Scalar %04x) after op: %08x\n", VEC_ACCUM_M(2), ACCUM_M(2), op); - if (VEC_ACCUM_M(3) != ACCUM_M(3)) fatalerror("ACCUM_M element 3 mismatch (SIMD %04x vs. Scalar %04x) after op: %08x\n", VEC_ACCUM_M(3), ACCUM_M(3), op); - if (VEC_ACCUM_M(4) != ACCUM_M(4)) fatalerror("ACCUM_M element 4 mismatch (SIMD %04x vs. Scalar %04x) after op: %08x\n", VEC_ACCUM_M(4), ACCUM_M(4), op); - if (VEC_ACCUM_M(5) != ACCUM_M(5)) fatalerror("ACCUM_M element 5 mismatch (SIMD %04x vs. Scalar %04x) after op: %08x\n", VEC_ACCUM_M(5), ACCUM_M(5), op); - if (VEC_ACCUM_M(6) != ACCUM_M(6)) fatalerror("ACCUM_M element 6 mismatch (SIMD %04x vs. Scalar %04x) after op: %08x\n", VEC_ACCUM_M(6), ACCUM_M(6), op); - if (VEC_ACCUM_M(7) != ACCUM_M(7)) fatalerror("ACCUM_M element 7 mismatch (SIMD %04x vs. Scalar %04x) after op: %08x\n", VEC_ACCUM_M(7), ACCUM_M(7), op); - if (VEC_ACCUM_L(0) != ACCUM_L(0)) fatalerror("ACCUM_L element 0 mismatch (SIMD %04x vs. Scalar %04x) after op: %08x\n", VEC_ACCUM_L(0), ACCUM_L(0), op); - if (VEC_ACCUM_L(1) != ACCUM_L(1)) fatalerror("ACCUM_L element 1 mismatch (SIMD %04x vs. Scalar %04x) after op: %08x\n", VEC_ACCUM_L(1), ACCUM_L(1), op); - if (VEC_ACCUM_L(2) != ACCUM_L(2)) fatalerror("ACCUM_L element 2 mismatch (SIMD %04x vs. Scalar %04x) after op: %08x\n", VEC_ACCUM_L(2), ACCUM_L(2), op); - if (VEC_ACCUM_L(3) != ACCUM_L(3)) fatalerror("ACCUM_L element 3 mismatch (SIMD %04x vs. Scalar %04x) after op: %08x\n", VEC_ACCUM_L(3), ACCUM_L(3), op); - if (VEC_ACCUM_L(4) != ACCUM_L(4)) fatalerror("ACCUM_L element 4 mismatch (SIMD %04x vs. Scalar %04x) after op: %08x\n", VEC_ACCUM_L(4), ACCUM_L(4), op); - if (VEC_ACCUM_L(5) != ACCUM_L(5)) fatalerror("ACCUM_L element 5 mismatch (SIMD %04x vs. Scalar %04x) after op: %08x\n", VEC_ACCUM_L(5), ACCUM_L(5), op); - if (VEC_ACCUM_L(6) != ACCUM_L(6)) fatalerror("ACCUM_L element 6 mismatch (SIMD %04x vs. Scalar %04x) after op: %08x\n", VEC_ACCUM_L(6), ACCUM_L(6), op); - if (VEC_ACCUM_L(7) != ACCUM_L(7)) fatalerror("ACCUM_L element 7 mismatch (SIMD %04x vs. Scalar %04x) after op: %08x\n", VEC_ACCUM_L(7), ACCUM_L(7), op); - for (int i = 0; i < 32; i++) - { - if (m_rsp_state->r[i] != m_scalar_r[i]) fatalerror("r[%d] mismatch (SIMD %08x vs. Scalar %08x) after op: %08x\n", i, m_rsp_state->r[i], m_scalar_r[i], op); - for (int el = 0; el < 8; el++) - { - UINT16 out; - SIMD_EXTRACT16(m_xv[i], out, el); - if ((UINT16)VREG_S(i, el) != out) fatalerror("Vector %d element %d mismatch (SIMD %04x vs. Scalar %04x) after op: %08x\n", i, el, out, (UINT16)VREG_S(i, el), op); - } - } - for (int i = 0; i < 4096; i++) - { - if (m_dmem8[i] != m_scalar_dmem[i]) fatalerror("dmem[%d] mismatch (SIMD %02x vs. Scalar %02x) after op: %08x\n", i, m_dmem8[i], m_scalar_dmem[i], op); - } - for (int i = 0; i < 5; i++) - { - for (int el = 0; el < 8; el++) - { - UINT16 out; - SIMD_EXTRACT16(m_xvflag[i], out, el); - if (m_vflag[i][el] != out) fatalerror("flag[%d][%d] mismatch (SIMD %04x vs. Scalar %04x) after op: %08x\n", i, el, out, m_vflag[i][el], op); - } - } -} - -static void cfunc_verify_regs(void *param) -{ - ((rsp_device *)param)->ccfunc_verify_regs(); -} -#endif - -#if USE_SIMD -int rsp_device::generate_lwc2(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) -{ - //int loopdest; - UINT32 op = desc->opptr.l[0]; - //int dest = (op >> 16) & 0x1f; - //int base = (op >> 21) & 0x1f; - //int index = (op >> 7) & 0xf; - int offset = (op & 0x7f); - //int skip; - if (offset & 0x40) - { - offset |= 0xffffffc0; - } - - switch ((op >> 11) & 0x1f) - { - case 0x00: /* LBV */ - //UML_ADD(block, I0, R32(RSREG), offset); - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_lbv_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_lbv_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - case 0x01: /* LSV */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_lsv_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_lsv_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - case 0x02: /* LLV */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_llv_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_llv_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - case 0x03: /* LDV */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_ldv_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_ldv_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - case 0x04: /* LQV */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_lqv_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_lqv_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - case 0x05: /* LRV */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_lrv_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_lrv_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - case 0x06: /* LPV */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_lpv_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_lpv_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - case 0x07: /* LUV */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_luv_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_luv_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - case 0x08: /* LHV */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_lhv_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_lhv_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - case 0x09: /* LFV */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_lfv_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_lfv_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - case 0x0a: /* LWV */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_lwv_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_lwv_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - case 0x0b: /* LTV */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_ltv_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_ltv_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - - default: - return FALSE; - } -} - -#else - -int rsp_device::generate_lwc2(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) -{ - //int loopdest; - UINT32 op = desc->opptr.l[0]; - //int dest = (op >> 16) & 0x1f; - //int base = (op >> 21) & 0x1f; - //int index = (op >> 7) & 0xf; - int offset = (op & 0x7f); - //int skip; - if (offset & 0x40) - { - offset |= 0xffffffc0; - } - - switch ((op >> 11) & 0x1f) - { - case 0x00: /* LBV */ - //UML_ADD(block, I0, R32(RSREG), offset); - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_lbv_scalar, this); - return TRUE; - case 0x01: /* LSV */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_lsv_scalar, this); - return TRUE; - case 0x02: /* LLV */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_llv_scalar, this); - return TRUE; - case 0x03: /* LDV */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_ldv_scalar, this); - return TRUE; - case 0x04: /* LQV */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_lqv_scalar, this); - return TRUE; - case 0x05: /* LRV */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_lrv_scalar, this); - return TRUE; - case 0x06: /* LPV */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_lpv_scalar, this); - return TRUE; - case 0x07: /* LUV */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_luv_scalar, this); - return TRUE; - case 0x08: /* LHV */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_lhv_scalar, this); - return TRUE; - case 0x09: /* LFV */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_lfv_scalar, this); - return TRUE; - case 0x0a: /* LWV */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_lwv_scalar, this); - return TRUE; - case 0x0b: /* LTV */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_ltv_scalar, this); - return TRUE; - - default: - return FALSE; - } -} -#endif - -#if USE_SIMD -// SBV -// -// 31 25 20 15 10 6 0 -// -------------------------------------------------- -// | 111010 | BBBBB | TTTTT | 00000 | IIII | Offset | -// -------------------------------------------------- -// -// Stores 1 byte from vector byte index - -inline void rsp_device::ccfunc_rsp_sbv_simd() -{ - UINT32 op = m_rsp_state->arg0; - 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 ea = (base) ? m_rsp_state->r[base] + offset : offset; - UINT16 value; - SIMD_EXTRACT16(m_xv[dest], value, (index >> 1)); - value >>= (1-(index & 1)) * 8; - DM_WRITE8(ea, (UINT8)value); -} - -static void cfunc_rsp_sbv_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_sbv_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_sbv_scalar() -{ - UINT32 op = m_rsp_state->arg0; - 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 ea = (base) ? m_rsp_state->r[base] + offset : offset; - DM_WRITE8(ea, VREG_B(dest, index)); -} - -static void cfunc_rsp_sbv_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_sbv_scalar(); -} -#endif - -#if USE_SIMD -// SSV -// -// 31 25 20 15 10 6 0 -// -------------------------------------------------- -// | 111010 | BBBBB | TTTTT | 00001 | IIII | Offset | -// -------------------------------------------------- -// -// Stores 2 bytes starting from vector byte index - -inline void rsp_device::ccfunc_rsp_ssv_simd() -{ - UINT32 op = m_rsp_state->arg0; - 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 ea = (base) ? m_rsp_state->r[base] + (offset * 2) : (offset * 2); - - int end = index + 2; - for (int i = index; i < end; i++) - { - UINT16 value; - SIMD_EXTRACT16(m_xv[dest], value, (i >> 1)); - value >>= (1 - (i & 1)) * 8; - DM_WRITE8(ea, (UINT8)value); - ea++; - } -} - -static void cfunc_rsp_ssv_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_ssv_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_ssv_scalar() -{ - UINT32 op = m_rsp_state->arg0; - 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 ea = (base) ? m_rsp_state->r[base] + (offset * 2) : (offset * 2); - - int end = index + 2; - for (int i = index; i < end; i++) - { - DM_WRITE8(ea, VREG_B(dest, i)); - ea++; - } -} - -static void cfunc_rsp_ssv_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_ssv_scalar(); -} -#endif - -#if USE_SIMD -// SLV -// -// 31 25 20 15 10 6 0 -// -------------------------------------------------- -// | 111010 | BBBBB | TTTTT | 00010 | IIII | Offset | -// -------------------------------------------------- -// -// Stores 4 bytes starting from vector byte index - -inline void rsp_device::ccfunc_rsp_slv_simd() -{ - UINT32 op = m_rsp_state->arg0; - 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 ea = (base) ? m_rsp_state->r[base] + (offset * 4) : (offset * 4); - - int end = index + 4; - for (int i = index; i < end; i++) - { - UINT16 value; - SIMD_EXTRACT16(m_xv[dest], value, (i >> 1)); - value >>= (1 - (i & 1)) * 8; - DM_WRITE8(ea, (UINT8)value); - ea++; - } -} - -static void cfunc_rsp_slv_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_slv_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_slv_scalar() -{ - UINT32 op = m_rsp_state->arg0; - 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 ea = (base) ? m_rsp_state->r[base] + (offset * 4) : (offset * 4); - - int end = index + 4; - for (int i = index; i < end; i++) - { - DM_WRITE8(ea, VREG_B(dest, i)); - ea++; - } -} - -static void cfunc_rsp_slv_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_slv_scalar(); -} -#endif - -#if USE_SIMD -// SDV -// -// 31 25 20 15 10 6 0 -// -------------------------------------------------- -// | 111010 | BBBBB | TTTTT | 00011 | IIII | Offset | -// -------------------------------------------------- -// -// Stores 8 bytes starting from vector byte index - -inline void rsp_device::ccfunc_rsp_sdv_simd() -{ - UINT32 op = m_rsp_state->arg0; - int dest = (op >> 16) & 0x1f; - int base = (op >> 21) & 0x1f; - int index = (op >> 7) & 0x8; - int offset = (op & 0x7f); - if (offset & 0x40) - { - offset |= 0xffffffc0; - } - UINT32 ea = (base) ? m_rsp_state->r[base] + (offset * 8) : (offset * 8); - - int end = index + 8; - for (int i = index; i < end; i++) - { - UINT16 value; - SIMD_EXTRACT16(m_xv[dest], value, (i >> 1)); - value >>= (1 - (i & 1)) * 8; - DM_WRITE8(ea, (UINT8)value); - ea++; - } -} - -static void cfunc_rsp_sdv_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_sdv_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_sdv_scalar() -{ - UINT32 op = m_rsp_state->arg0; - int dest = (op >> 16) & 0x1f; - int base = (op >> 21) & 0x1f; - int index = (op >> 7) & 0x8; - int offset = (op & 0x7f); - if (offset & 0x40) - { - offset |= 0xffffffc0; - } - UINT32 ea = (base) ? m_rsp_state->r[base] + (offset * 8) : (offset * 8); - - int end = index + 8; - for (int i = index; i < end; i++) - { - DM_WRITE8(ea, VREG_B(dest, i)); - ea++; - } -} - -static void cfunc_rsp_sdv_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_sdv_scalar(); -} -#endif - -#if USE_SIMD -// 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 - -inline void rsp_device::ccfunc_rsp_sqv_simd() -{ - UINT32 op = m_rsp_state->arg0; - 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 ea = (base) ? m_rsp_state->r[base] + (offset * 16) : (offset * 16); - int end = index + (16 - (ea & 0xf)); - for (int i=index; i < end; i++) - { - UINT16 value; - SIMD_EXTRACT16(m_xv[dest], value, (i >> 1)); - value >>= (1-(i & 1)) * 8; - DM_WRITE8(ea, (UINT8)value); - ea++; - } -} - -static void cfunc_rsp_sqv_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_sqv_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_sqv_scalar() -{ - UINT32 op = m_rsp_state->arg0; - 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 ea = (base) ? m_rsp_state->r[base] + (offset * 16) : (offset * 16); - int end = index + (16 - (ea & 0xf)); - for (int i=index; i < end; i++) - { - DM_WRITE8(ea, VREG_B(dest, i & 0xf)); - ea++; - } -} - -static void cfunc_rsp_sqv_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_sqv_scalar(); -} -#endif - -#if USE_SIMD -// 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 - -inline void rsp_device::ccfunc_rsp_srv_simd() -{ - UINT32 op = m_rsp_state->arg0; - 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 ea = (base) ? 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++) - { - UINT32 bi = (i + o) & 0xf; - UINT16 value; - SIMD_EXTRACT16(m_xv[dest], value, (bi >> 1)); - value >>= (1-(bi & 1)) * 8; - DM_WRITE8(ea, (UINT8)value); - ea++; - } -} - -static void cfunc_rsp_srv_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_srv_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_srv_scalar() -{ - UINT32 op = m_rsp_state->arg0; - 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 ea = (base) ? 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++) - { - DM_WRITE8(ea, VREG_B(dest, ((i + o) & 0xf))); - ea++; - } -} - -static void cfunc_rsp_srv_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_srv_scalar(); -} -#endif - -#if USE_SIMD -// SPV -// -// 31 25 20 15 10 6 0 -// -------------------------------------------------- -// | 111010 | BBBBB | TTTTT | 00110 | IIII | Offset | -// -------------------------------------------------- -// -// Stores upper 8 bits of each element - -inline void rsp_device::ccfunc_rsp_spv_simd() -{ - UINT32 op = m_rsp_state->arg0; - 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 ea = (base) ? m_rsp_state->r[base] + (offset * 8) : (offset * 8); - int end = index + 8; - for (int i=index; i < end; i++) - { - if ((i & 0xf) < 8) - { - UINT16 value; - SIMD_EXTRACT16(m_xv[dest], value, i); - DM_WRITE8(ea, (UINT8)(value >> 8)); - } - else - { - UINT16 value; - SIMD_EXTRACT16(m_xv[dest], value, i); - DM_WRITE8(ea, (UINT8)(value >> 7)); - } - ea++; - } -} - -static void cfunc_rsp_spv_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_spv_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_spv_scalar() -{ - UINT32 op = m_rsp_state->arg0; - 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 ea = (base) ? m_rsp_state->r[base] + (offset * 8) : (offset * 8); - int end = index + 8; - for (int i=index; i < end; i++) - { - if ((i & 0xf) < 8) - { - DM_WRITE8(ea, VREG_B(dest, (i & 0xf) << 1)); - } - else - { - DM_WRITE8(ea, VREG_S(dest, (i & 0x7)) >> 7); - } - ea++; - } -} - -static void cfunc_rsp_spv_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_spv_scalar(); -} -#endif - -#if USE_SIMD -// SUV -// -// 31 25 20 15 10 6 0 -// -------------------------------------------------- -// | 111010 | BBBBB | TTTTT | 00111 | IIII | Offset | -// -------------------------------------------------- -// -// Stores bits 14-7 of each element - -inline void rsp_device::ccfunc_rsp_suv_simd() -{ - UINT32 op = m_rsp_state->arg0; - 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 ea = (base) ? m_rsp_state->r[base] + (offset * 8) : (offset * 8); - int end = index + 8; - for (int i=index; i < end; i++) - { - if ((i & 0xf) < 8) - { - UINT16 value; - SIMD_EXTRACT16(m_xv[dest], value, i); - DM_WRITE8(ea, (UINT8)(value >> 7)); - } - else - { - UINT16 value; - SIMD_EXTRACT16(m_xv[dest], value, i); - DM_WRITE8(ea, (UINT8)(value >> 8)); - } - ea++; - } -} - -static void cfunc_rsp_suv_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_suv_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_suv_scalar() -{ - UINT32 op = m_rsp_state->arg0; - 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 ea = (base) ? m_rsp_state->r[base] + (offset * 8) : (offset * 8); - int end = index + 8; - for (int i=index; i < end; i++) - { - if ((i & 0xf) < 8) - { - DM_WRITE8(ea, VREG_S(dest, (i & 0x7)) >> 7); - } - else - { - DM_WRITE8(ea, VREG_B(dest, ((i & 0x7) << 1))); - } - ea++; - } -} - -static void cfunc_rsp_suv_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_suv_scalar(); -} -#endif - -#if USE_SIMD -// 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 - -inline void rsp_device::ccfunc_rsp_shv_simd() -{ - UINT32 op = m_rsp_state->arg0; - 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 ea = (base) ? m_rsp_state->r[base] + (offset * 16) : (offset * 16); - for (int i=0; i < 8; i++) - { - int element = index + (i << 1); - UINT16 value; - SIMD_EXTRACT16(m_xv[dest], value, element >> 1); - DM_WRITE8(ea, (value >> 7) & 0x00ff); - ea += 2; - } -} - -static void cfunc_rsp_shv_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_shv_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_shv_scalar() -{ - UINT32 op = m_rsp_state->arg0; - 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 ea = (base) ? m_rsp_state->r[base] + (offset * 16) : (offset * 16); - for (int i=0; i < 8; i++) - { - int element = index + (i << 1); - UINT8 d = (VREG_B(dest, (element & 0xf)) << 1) | - (VREG_B(dest, ((element + 1) & 0xf)) >> 7); - DM_WRITE8(ea, d); - ea += 2; - } -} - -static void cfunc_rsp_shv_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_shv_scalar(); -} -#endif - -#if USE_SIMD -// 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 - -inline void rsp_device::ccfunc_rsp_sfv_simd() -{ - UINT32 op = m_rsp_state->arg0; - 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 ea = (base) ? 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++) - { - UINT16 value; - SIMD_EXTRACT16(m_xv[dest], value, i); - DM_WRITE8(ea + (eaoffset & 0xf), (value >> 7) & 0x00ff); - eaoffset += 4; - } -} - -static void cfunc_rsp_sfv_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_sfv_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_sfv_scalar() -{ - UINT32 op = m_rsp_state->arg0; - 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 ea = (base) ? 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++) - { - DM_WRITE8(ea + (eaoffset & 0xf), VREG_S(dest, i) >> 7); - eaoffset += 4; - } -} - -static void cfunc_rsp_sfv_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_sfv_scalar(); -} -#endif - -#if USE_SIMD -// 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 - -inline void rsp_device::ccfunc_rsp_swv_simd() -{ - UINT32 op = m_rsp_state->arg0; - 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 ea = (base) ? 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++) - { - UINT16 value; - SIMD_EXTRACT16(m_xv[dest], value, i >> 1); - DM_WRITE8(ea + (eaoffset & 0xf), (value >> ((1-(i & 1)) * 8)) & 0xff); - eaoffset++; - } -} - -static void cfunc_rsp_swv_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_swv_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_swv_scalar() -{ - UINT32 op = m_rsp_state->arg0; - 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 ea = (base) ? 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++) - { - DM_WRITE8(ea + (eaoffset & 0xf), VREG_B(dest, i & 0xf)); - eaoffset++; - } -} - -static void cfunc_rsp_swv_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_swv_scalar(); -} -#endif - -#if USE_SIMD -// 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 - -inline void rsp_device::ccfunc_rsp_stv_simd() -{ - UINT32 op = m_rsp_state->arg0; - 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 ea = (base) ? m_rsp_state->r[base] + (offset * 16) : (offset * 16); - int eaoffset = (ea & 0xf) + (element * 2); - ea &= ~0xf; - - for (int i = vs; i < ve; i++) - { - UINT16 value; - SIMD_EXTRACT16(m_xv[i], value, element); - DM_WRITE16(ea + (eaoffset & 0xf), value); - eaoffset += 2; - element++; - } -} - -static void cfunc_rsp_stv_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_stv_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_stv_scalar() -{ - UINT32 op = m_rsp_state->arg0; - 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 ea = (base) ? m_rsp_state->r[base] + (offset * 16) : (offset * 16); - int eaoffset = (ea & 0xf) + (element * 2); - ea &= ~0xf; - - for (int i = vs; i < ve; i++) - { - DM_WRITE16(ea + (eaoffset & 0xf), VREG_S(i, element & 0x7)); - eaoffset += 2; - element++; - } -} - -static void cfunc_rsp_stv_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_stv_scalar(); -} -#endif - -#if USE_SIMD -int rsp_device::generate_swc2(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) -{ -// int loopdest; - UINT32 op = desc->opptr.l[0]; - //int dest = (op >> 16) & 0x1f; - //int base = (op >> 21) & 0x1f; - //int index = (op >> 7) & 0xf; - int offset = (op & 0x7f); - //int skip; - if (offset & 0x40) - { - offset |= 0xffffffc0; - } - - switch ((op >> 11) & 0x1f) - { - case 0x00: /* SBV */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_sbv_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_sbv_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - case 0x01: /* SSV */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_ssv_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_ssv_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - case 0x02: /* SLV */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_slv_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_slv_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - case 0x03: /* SDV */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_sdv_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_sdv_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - case 0x04: /* SQV */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_sqv_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_sqv_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - case 0x05: /* SRV */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_srv_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_srv_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - case 0x06: /* SPV */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_spv_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_spv_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - case 0x07: /* SUV */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_suv_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_suv_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - case 0x08: /* SHV */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_shv_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_shv_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - case 0x09: /* SFV */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_sfv_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_sfv_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - case 0x0a: /* SWV */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_swv_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_swv_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - case 0x0b: /* STV */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_stv_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_stv_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - - default: - unimplemented_opcode(op); - return FALSE; - } - - return TRUE; -} - -#else - -int rsp_device::generate_swc2(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) -{ -// int loopdest; - UINT32 op = desc->opptr.l[0]; - //int dest = (op >> 16) & 0x1f; - //int base = (op >> 21) & 0x1f; - //int index = (op >> 7) & 0xf; - int offset = (op & 0x7f); - //int skip; - if (offset & 0x40) - { - offset |= 0xffffffc0; - } - - switch ((op >> 11) & 0x1f) - { - case 0x00: /* SBV */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_sbv_scalar, this); - return TRUE; - case 0x01: /* SSV */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_ssv_scalar, this); - return TRUE; - case 0x02: /* SLV */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_slv_scalar, this); - return TRUE; - case 0x03: /* SDV */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_sdv_scalar, this); - return TRUE; - case 0x04: /* SQV */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_sqv_scalar, this); - return TRUE; - case 0x05: /* SRV */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_srv_scalar, this); - return TRUE; - case 0x06: /* SPV */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_spv_scalar, this); - return TRUE; - case 0x07: /* SUV */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_suv_scalar, this); - return TRUE; - case 0x08: /* SHV */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_shv_scalar, this); - return TRUE; - case 0x09: /* SFV */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_sfv_scalar, this); - return TRUE; - case 0x0a: /* SWV */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_swv_scalar, this); - return TRUE; - case 0x0b: /* STV */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_stv_scalar, this); - return TRUE; - - default: - unimplemented_opcode(op); - return FALSE; - } - - return TRUE; -} -#endif - -#if USE_SIMD -inline UINT16 rsp_device::VEC_SATURATE_ACCUM(int accum, int slice, UINT16 negative, UINT16 positive) -{ - if ((INT16)VEC_ACCUM_H(accum) < 0) - { - if ((UINT16)(VEC_ACCUM_H(accum)) != 0xffff) - { - return negative; - } - else - { - if ((INT16)VEC_ACCUM_M(accum) >= 0) - { - return negative; - } - else - { - if (slice == 0) - { - return VEC_ACCUM_L(accum); - } - else if (slice == 1) - { - return VEC_ACCUM_M(accum); - } - } - } - } - else - { - if ((UINT16)(VEC_ACCUM_H(accum)) != 0) - { - return positive; - } - else - { - if ((INT16)VEC_ACCUM_M(accum) < 0) - { - return positive; - } - else - { - if (slice == 0) - { - return VEC_ACCUM_L(accum); - } - else - { - return VEC_ACCUM_M(accum); - } - } - } - } - return 0; -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) -inline UINT16 rsp_device::SATURATE_ACCUM(int accum, int slice, UINT16 negative, UINT16 positive) -{ - if ((INT16)ACCUM_H(accum) < 0) - { - if ((UINT16)(ACCUM_H(accum)) != 0xffff) - { - return negative; - } - else - { - if ((INT16)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)(ACCUM_H(accum)) != 0) - { - return positive; - } - else - { - if ((INT16)ACCUM_M(accum) < 0) - { - return positive; - } - else - { - if (slice == 0) - { - return ACCUM_L(accum); - } - else - { - return ACCUM_M(accum); - } - } - } - } - return 0; -} -#endif - -inline UINT16 rsp_device::SATURATE_ACCUM1(int accum, UINT16 negative, UINT16 positive) -{ - // Return negative if H<0 && (H!=0xffff || M >= 0) - // Return positive if H>0 || (H==0 && M<0) - // Return medium slice if H==0xffff && M<0 - // Return medium slice if H==0 && M>=0 - if ((INT16)ACCUM_H(accum) < 0) - { - if ((UINT16)(ACCUM_H(accum)) != 0xffff) - { - return negative; - } - else - { - if ((INT16)ACCUM_M(accum) >= 0) - { - return negative; - } - else - { - return ACCUM_M(accum); - } - } - } - else - { - if ((UINT16)(ACCUM_H(accum)) != 0) - { - return positive; - } - else - { - if ((INT16)ACCUM_M(accum) < 0) - { - return positive; - } - else - { - return ACCUM_M(accum); - } - } - } - // never executed - //return 0; -} - -#if USE_SIMD -#define VEC_WRITEBACK_RESULT() { \ - SIMD_INSERT16(m_xv[VDREG], vres[0], 0); \ - SIMD_INSERT16(m_xv[VDREG], vres[1], 1); \ - SIMD_INSERT16(m_xv[VDREG], vres[2], 2); \ - SIMD_INSERT16(m_xv[VDREG], vres[3], 3); \ - SIMD_INSERT16(m_xv[VDREG], vres[4], 4); \ - SIMD_INSERT16(m_xv[VDREG], vres[5], 5); \ - SIMD_INSERT16(m_xv[VDREG], vres[6], 6); \ - SIMD_INSERT16(m_xv[VDREG], vres[7], 7); \ -} -#endif - -#define WRITEBACK_RESULT() { \ - W_VREG_S(VDREG, 0) = vres[0]; \ - W_VREG_S(VDREG, 1) = vres[1]; \ - W_VREG_S(VDREG, 2) = vres[2]; \ - W_VREG_S(VDREG, 3) = vres[3]; \ - W_VREG_S(VDREG, 4) = vres[4]; \ - W_VREG_S(VDREG, 5) = vres[5]; \ - W_VREG_S(VDREG, 6) = vres[6]; \ - W_VREG_S(VDREG, 7) = vres[7]; \ -} - -#if USE_SIMD -/* ============================================================================ -* RSPPackLo32to16: Pack LSBs of 32-bit vectors to 16-bits without saturation. -* TODO: 5 SSE2 operations is kind of expensive just to truncate values? -* ========================================================================= */ -INLINE __m128i RSPPackLo32to16(__m128i vectorLow, __m128i vectorHigh) -{ - vectorLow = _mm_slli_epi32(vectorLow, 16); - vectorHigh = _mm_slli_epi32(vectorHigh, 16); - vectorLow = _mm_srai_epi32(vectorLow, 16); - vectorHigh = _mm_srai_epi32(vectorHigh, 16); - return _mm_packs_epi32(vectorLow, vectorHigh); -} - -/* ============================================================================ -* RSPPackHi32to16: Pack MSBs of 32-bit vectors to 16-bits without saturation. -* ========================================================================= */ -INLINE __m128i RSPPackHi32to16(__m128i vectorLow, __m128i vectorHigh) -{ - vectorLow = _mm_srai_epi32(vectorLow, 16); - vectorHigh = _mm_srai_epi32(vectorHigh, 16); - return _mm_packs_epi32(vectorLow, vectorHigh); -} - -/* ============================================================================ -* RSPSignExtend16to32: Sign-extend 16-bit slices to 32-bit slices. -* ========================================================================= */ -INLINE void RSPSignExtend16to32(__m128i source, __m128i *vectorLow, __m128i *vectorHigh) -{ - __m128i vMask = _mm_srai_epi16(source, 15); - *vectorHigh = _mm_unpackhi_epi16(source, vMask); - *vectorLow = _mm_unpacklo_epi16(source, vMask); -} - -/* ============================================================================ -* RSPZeroExtend16to32: Zero-extend 16-bit slices to 32-bit slices. -* ========================================================================= */ -INLINE void RSPZeroExtend16to32(__m128i source, __m128i *vectorLow, __m128i *vectorHigh) -{ - *vectorHigh = _mm_unpackhi_epi16(source, _mm_setzero_si128()); - *vectorLow = _mm_unpacklo_epi16(source, _mm_setzero_si128()); -} - -/* ============================================================================ -* _mm_mullo_epi32: SSE2 lacks _mm_mullo_epi32, define it manually. -* TODO/WARNING/DISCLAIMER: Assumes one argument is positive. -* ========================================================================= */ -INLINE __m128i _mm_mullo_epi32(__m128i a, __m128i b) -{ - __m128i a4 = _mm_srli_si128(a, 4); - __m128i b4 = _mm_srli_si128(b, 4); - __m128i ba = _mm_mul_epu32(b, a); - __m128i b4a4 = _mm_mul_epu32(b4, a4); - - __m128i mask = _mm_setr_epi32(~0, 0, ~0, 0); - __m128i baMask = _mm_and_si128(ba, mask); - __m128i b4a4Mask = _mm_and_si128(b4a4, mask); - __m128i b4a4MaskShift = _mm_slli_si128(b4a4Mask, 4); - - return _mm_or_si128(baMask, b4a4MaskShift); -} - -/* ============================================================================ -* RSPClampLowToVal: Clamps the low word of the accumulator. -* ========================================================================= */ -INLINE __m128i RSPClampLowToVal(__m128i vaccLow, __m128i vaccMid, __m128i vaccHigh) -{ - __m128i setMask = _mm_cmpeq_epi16(_mm_setzero_si128(), _mm_setzero_si128()); - __m128i negCheck, useValMask, negVal, posVal; - - /* Compute some common values ahead of time. */ - negCheck = _mm_cmplt_epi16(vaccHigh, _mm_setzero_si128()); - - /* If accmulator < 0, clamp to val if val != TMin. */ - useValMask = _mm_and_si128(vaccHigh, _mm_srai_epi16(vaccMid, 15)); - useValMask = _mm_cmpeq_epi16(useValMask, setMask); - negVal = _mm_and_si128(useValMask, vaccLow); - - /* Otherwise, clamp to ~0 if any high bits are set. */ - useValMask = _mm_or_si128(vaccHigh, _mm_srai_epi16(vaccMid, 15)); - useValMask = _mm_cmpeq_epi16(useValMask, _mm_setzero_si128()); - posVal = _mm_and_si128(useValMask, vaccLow); - - negVal = _mm_and_si128(negCheck, negVal); - posVal = _mm_andnot_si128(negCheck, posVal); - return _mm_or_si128(negVal, posVal); -} -#endif - -#if USE_SIMD -// VMULF -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000000 | -// ------------------------------------------------------ -// -// Multiplies signed integer by signed integer * 2 - -inline void rsp_device::ccfunc_rsp_vmulf_simd() -{ - int op = m_rsp_state->arg0; - - INT16 vres[8]; - for (int i = 0; i < 8; i++) - { - UINT16 w1, w2; - VEC_GET_SCALAR_VS1(w1, i); - VEC_GET_SCALAR_VS2(w2, i); - INT32 s1 = (INT32)(INT16)w1; - INT32 s2 = (INT32)(INT16)w2; - - if (s1 == -32768 && s2 == -32768) - { - // overflow - VEC_SET_ACCUM_H(0, i); - VEC_SET_ACCUM_M(-32768, i); - VEC_SET_ACCUM_L(-32768, i); - vres[i] = 0x7fff; - } - else - { - INT64 r = s1 * s2 * 2; - r += 0x8000; // rounding ? - VEC_SET_ACCUM_H((r < 0) ? 0xffff : 0, i); - VEC_SET_ACCUM_M((INT16)(r >> 16), i); - VEC_SET_ACCUM_L((UINT16)(r), i); - vres[i] = VEC_ACCUM_M(i); - } - } - VEC_WRITEBACK_RESULT(); -} - -static void cfunc_rsp_vmulf_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vmulf_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_vmulf_scalar() -{ - int op = m_rsp_state->arg0; - - INT16 vres[8]; - for (int i = 0; i < 8; i++) - { - UINT16 w1, w2; - SCALAR_GET_VS1(w1, i); - SCALAR_GET_VS2(w2, i); - INT32 s1 = (INT32)(INT16)w1; - INT32 s2 = (INT32)(INT16)w2; - - if (s1 == -32768 && s2 == -32768) - { - // overflow - SET_ACCUM_H(0, i); - SET_ACCUM_M(-32768, i); - SET_ACCUM_L(-32768, i); - vres[i] = 0x7fff; - } - else - { - INT64 r = s1 * s2 * 2; - r += 0x8000; // rounding ? - SET_ACCUM_H((r < 0) ? 0xffff : 0, i); - SET_ACCUM_M((INT16)(r >> 16), i); - SET_ACCUM_L((UINT16)(r), i); - vres[i] = ACCUM_M(i); - } - } - WRITEBACK_RESULT(); -} - -static void cfunc_rsp_vmulf_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vmulf_scalar(); -} -#endif - -#if USE_SIMD -// VMULU -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000001 | -// ------------------------------------------------------ -// - -inline void rsp_device::ccfunc_rsp_vmulu_simd() -{ - int op = m_rsp_state->arg0; - - INT16 vres[8]; - for (int i = 0; i < 8; i++) - { - UINT16 w1, w2; - VEC_GET_SCALAR_VS1(w1, i); - VEC_GET_SCALAR_VS2(w2, i); - INT32 s1 = (INT32)(INT16)w1; - INT32 s2 = (INT32)(INT16)w2; - - INT64 r = s1 * s2 * 2; - r += 0x8000; // rounding ? - - VEC_SET_ACCUM_H((UINT16)(r >> 32), i); - VEC_SET_ACCUM_M((UINT16)(r >> 16), i); - VEC_SET_ACCUM_L((UINT16)(r), i); - - if (r < 0) - { - vres[i] = 0; - } - else if (((INT16)(VEC_ACCUM_H(i)) ^ (INT16)(VEC_ACCUM_M(i))) < 0) - { - vres[i] = -1; - } - else - { - vres[i] = VEC_ACCUM_M(i); - } - } - VEC_WRITEBACK_RESULT(); -} - -static void cfunc_rsp_vmulu_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vmulu_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_vmulu_scalar() -{ - int op = m_rsp_state->arg0; - - INT16 vres[8]; - for (int i = 0; i < 8; i++) - { - UINT16 w1, w2; - SCALAR_GET_VS1(w1, i); - SCALAR_GET_VS2(w2, i); - INT32 s1 = (INT32)(INT16)w1; - INT32 s2 = (INT32)(INT16)w2; - - INT64 r = s1 * s2 * 2; - r += 0x8000; // rounding ? - - SET_ACCUM_H((UINT16)(r >> 32), i); - SET_ACCUM_M((UINT16)(r >> 16), i); - SET_ACCUM_L((UINT16)(r), i); - - if (r < 0) - { - vres[i] = 0; - } - else if (((INT16)(ACCUM_H(i)) ^ (INT16)(ACCUM_M(i))) < 0) - { - vres[i] = -1; - } - else - { - vres[i] = ACCUM_M(i); - } - } - WRITEBACK_RESULT(); -} - -static void cfunc_rsp_vmulu_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vmulu_scalar(); -} -#endif - -#if USE_SIMD -// 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 - -inline void rsp_device::ccfunc_rsp_vmudl_simd() -{ - int op = m_rsp_state->arg0; - - __m128i vsReg = m_xv[VS1REG]; - __m128i vtReg = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); - - /* Unpack to obtain for 32-bit precision. */ - __m128i unpackLo = _mm_mullo_epi16(vsReg, vtReg); - __m128i unpackHi = _mm_mulhi_epu16(vsReg, vtReg); - __m128i loProduct = _mm_unpacklo_epi16(unpackLo, unpackHi); - __m128i hiProduct = _mm_unpackhi_epi16(unpackLo, unpackHi); - - m_xv[VDREG] = m_accum_l = RSPPackHi32to16(loProduct, hiProduct); - - m_accum_m = _mm_setzero_si128(); - m_accum_h = _mm_setzero_si128(); -} - -static void cfunc_rsp_vmudl_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vmudl_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_vmudl_scalar() -{ - int op = m_rsp_state->arg0; - - INT16 vres[8]; - for (int i = 0; i < 8; i++) - { - UINT16 w1, w2; - SCALAR_GET_VS1(w1, i); - SCALAR_GET_VS2(w2, i); - UINT32 s1 = (UINT32)(UINT16)w1; - UINT32 s2 = (UINT32)(UINT16)w2; - - UINT32 r = s1 * s2; - - SET_ACCUM_H(0, i); - SET_ACCUM_M(0, i); - SET_ACCUM_L((UINT16)(r >> 16), i); - - vres[i] = ACCUM_L(i); - } - WRITEBACK_RESULT(); -} - -static void cfunc_rsp_vmudl_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vmudl_scalar(); -} -#endif - -#if USE_SIMD -// 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 - -inline void rsp_device::ccfunc_rsp_vmudm_simd() -{ - int op = m_rsp_state->arg0; - - __m128i vsRegLo, vsRegHi, vtRegLo, vtRegHi; - - __m128i vsReg = m_xv[VS1REG]; - __m128i vtReg = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); - - /* Unpack to obtain for 32-bit precision. */ - RSPSignExtend16to32(vsReg, &vsRegLo, &vsRegHi); - RSPZeroExtend16to32(vtReg, &vtRegLo, &vtRegHi); - - /* Begin accumulating the products. */ - __m128i loProduct = _mm_mullo_epi32(vsRegLo, vtRegLo); - __m128i hiProduct = _mm_mullo_epi32(vsRegHi, vtRegHi); - m_accum_l = RSPPackLo32to16(loProduct, hiProduct); - m_accum_m = m_xv[VDREG] = RSPPackHi32to16(loProduct, hiProduct); - - loProduct = _mm_cmplt_epi32(loProduct, _mm_setzero_si128()); - hiProduct = _mm_cmplt_epi32(hiProduct, _mm_setzero_si128()); - m_accum_h = _mm_packs_epi32(loProduct, hiProduct); -} - -static void cfunc_rsp_vmudm_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vmudm_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_vmudm_scalar() -{ - int op = m_rsp_state->arg0; - - INT16 vres[8]; - for (int i = 0; i < 8; i++) - { - UINT16 w1, w2; - SCALAR_GET_VS1(w1, i); - SCALAR_GET_VS2(w2, i); - INT32 s1 = (INT32)(INT16)w1; - INT32 s2 = (UINT16)w2; - - INT32 r = s1 * s2; - - SET_ACCUM_H((r < 0) ? 0xffff : 0, i); // sign-extend to 48-bit - SET_ACCUM_M((INT16)(r >> 16), i); - SET_ACCUM_L((UINT16)r, i); - - vres[i] = ACCUM_M(i); - } - WRITEBACK_RESULT(); -} - -static void cfunc_rsp_vmudm_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vmudm_scalar(); -} -#endif - -#if USE_SIMD -// 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 - -inline void rsp_device::ccfunc_rsp_vmudn_simd() -{ - int op = m_rsp_state->arg0; - - __m128i vsRegLo, vsRegHi, vtRegLo, vtRegHi; - - __m128i vsReg = m_xv[VS1REG]; - __m128i vtReg = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); - - /* Unpack to obtain for 32-bit precision. */ - RSPZeroExtend16to32(vsReg, &vsRegLo, &vsRegHi); - RSPSignExtend16to32(vtReg, &vtRegLo, &vtRegHi); - - /* Begin accumulating the products. */ - __m128i loProduct = _mm_mullo_epi32(vsRegLo, vtRegLo); - __m128i hiProduct = _mm_mullo_epi32(vsRegHi, vtRegHi); - m_xv[VDREG] = m_accum_l = RSPPackLo32to16(loProduct, hiProduct); - m_accum_m = RSPPackHi32to16(loProduct, hiProduct); - m_accum_h = _mm_cmplt_epi16(m_accum_m, _mm_setzero_si128()); -} - -static void cfunc_rsp_vmudn_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vmudn_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_vmudn_scalar() -{ - int op = m_rsp_state->arg0; - - INT16 vres[8] = { 0 }; - for (int i = 0; i < 8; i++) - { - UINT16 w1, w2; - SCALAR_GET_VS1(w1, i); - SCALAR_GET_VS2(w2, i); - INT32 s1 = (UINT16)w1; - INT32 s2 = (INT32)(INT16)w2; - - INT32 r = s1 * s2; - - SET_ACCUM_H((r < 0) ? 0xffff : 0, i); // sign-extend to 48-bit - SET_ACCUM_M((INT16)(r >> 16), i); - SET_ACCUM_L((UINT16)(r), i); - - vres[i] = (UINT16)(r); - } - WRITEBACK_RESULT(); -} - -static void cfunc_rsp_vmudn_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vmudn_scalar(); -} -#endif - -#if USE_SIMD -// 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 - -inline void rsp_device::ccfunc_rsp_vmudh_simd() -{ - int op = m_rsp_state->arg0; - - __m128i vaccLow, vaccHigh; - __m128i unpackLo, unpackHi; - - __m128i vsReg = m_xv[VS1REG]; - __m128i vtReg = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); - - /* Multiply the sources, accumulate the product. */ - unpackLo = _mm_mullo_epi16(vsReg, vtReg); - unpackHi = _mm_mulhi_epi16(vsReg, vtReg); - vaccHigh = _mm_unpackhi_epi16(unpackLo, unpackHi); - vaccLow = _mm_unpacklo_epi16(unpackLo, unpackHi); - - /* Pack the accumulator and result back up. */ - m_xv[VDREG] = _mm_packs_epi32(vaccLow, vaccHigh); - m_accum_l = _mm_setzero_si128(); - m_accum_m = RSPPackLo32to16(vaccLow, vaccHigh); - m_accum_h = RSPPackHi32to16(vaccLow, vaccHigh); -} - -static void cfunc_rsp_vmudh_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vmudh_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_vmudh_scalar() -{ - int op = m_rsp_state->arg0; - - INT16 vres[8]; - for (int i = 0; i < 8; i++) - { - UINT16 w1, w2; - SCALAR_GET_VS1(w1, i); - SCALAR_GET_VS2(w2, i); - INT32 s1 = (INT32)(INT16)w1; - INT32 s2 = (INT32)(INT16)w2; - - INT32 r = s1 * s2; - - SET_ACCUM_H((INT16)(r >> 16), i); - SET_ACCUM_M((UINT16)(r), i); - SET_ACCUM_L(0, i); - - if (r < -32768) r = -32768; - if (r > 32767) r = 32767; - vres[i] = (INT16)(r); - } - WRITEBACK_RESULT(); -} - -static void cfunc_rsp_vmudh_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vmudh_scalar(); -} -#endif - -#if USE_SIMD -// VMACF -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001000 | -// ------------------------------------------------------ -// - -inline void rsp_device::ccfunc_rsp_vmacf_simd() -{ - int op = m_rsp_state->arg0; - - INT16 vres[8]; - for (int i = 0; i < 8; i++) - { - UINT16 w1, w2; - VEC_GET_SCALAR_VS1(w1, i); - VEC_GET_SCALAR_VS2(w2, i); - INT32 s1 = (INT32)(INT16)w1; - INT32 s2 = (INT32)(INT16)w2; - - INT32 r = s1 * s2; - - UINT64 q = (UINT64)(UINT16)VEC_ACCUM_LL(i); - q |= (((UINT64)(UINT16)VEC_ACCUM_L(i)) << 16); - q |= (((UINT64)(UINT16)VEC_ACCUM_M(i)) << 32); - q |= (((UINT64)(UINT16)VEC_ACCUM_H(i)) << 48); - - q += (INT64)(r) << 17; - VEC_SET_ACCUM_LL((UINT16)q, i); - VEC_SET_ACCUM_L((UINT16)(q >> 16), i); - VEC_SET_ACCUM_M((UINT16)(q >> 32), i); - VEC_SET_ACCUM_H((UINT16)(q >> 48), i); - - vres[i] = VEC_SATURATE_ACCUM(i, 1, 0x8000, 0x7fff); - } - VEC_WRITEBACK_RESULT(); -/* - __m128i loProduct, hiProduct, unpackLo, unpackHi; - __m128i vaccHigh; - __m128i vdReg, vdRegLo, vdRegHi; - - __m128i vsReg = m_xv[VS1REG]; - __m128i vtReg = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); - - __m128i vaccLow = m_accum_l; - - // Unpack to obtain for 32-bit precision. - RSPZeroExtend16to32(vaccLow, &vaccLow, &vaccHigh); - - // Begin accumulating the products. - unpackLo = _mm_mullo_epi16(vsReg, vtReg); - unpackHi = _mm_mulhi_epi16(vsReg, vtReg); - loProduct = _mm_unpacklo_epi16(unpackLo, unpackHi); - hiProduct = _mm_unpackhi_epi16(unpackLo, unpackHi); - loProduct = _mm_slli_epi32(loProduct, 1); - hiProduct = _mm_slli_epi32(hiProduct, 1); - - vdRegLo = _mm_srli_epi32(loProduct, 16); - vdRegHi = _mm_srli_epi32(hiProduct, 16); - vdRegLo = _mm_slli_epi32(vdRegLo, 16); - vdRegHi = _mm_slli_epi32(vdRegHi, 16); - vdRegLo = _mm_xor_si128(vdRegLo, loProduct); - vdRegHi = _mm_xor_si128(vdRegHi, hiProduct); - - vaccLow = _mm_add_epi32(vaccLow, vdRegLo); - vaccHigh = _mm_add_epi32(vaccHigh, vdRegHi); - - m_accum_l = vdReg = RSPPackLo32to16(vaccLow, vaccHigh); - - // Multiply the MSB of sources, accumulate the product. - vdRegLo = _mm_unpacklo_epi16(m_accum_m, m_accum_h); - vdRegHi = _mm_unpackhi_epi16(m_accum_m, m_accum_h); - - loProduct = _mm_srai_epi32(loProduct, 16); - hiProduct = _mm_srai_epi32(hiProduct, 16); - vaccLow = _mm_srai_epi32(vaccLow, 16); - vaccHigh = _mm_srai_epi32(vaccHigh, 16); - - vaccLow = _mm_add_epi32(loProduct, vaccLow); - vaccHigh = _mm_add_epi32(hiProduct, vaccHigh); - vaccLow = _mm_add_epi32(vdRegLo, vaccLow); - vaccHigh = _mm_add_epi32(vdRegHi, vaccHigh); - - // Clamp the accumulator and write it all out. - m_xv[VDREG] = _mm_packs_epi32(vaccLow, vaccHigh); - m_accum_m = RSPPackLo32to16(vaccLow, vaccHigh); - m_accum_h = RSPPackHi32to16(vaccLow, vaccHigh); -*/ -} - -static void cfunc_rsp_vmacf_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vmacf_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_vmacf_scalar() -{ - int op = m_rsp_state->arg0; - - INT16 vres[8]; - for (int i = 0; i < 8; i++) - { - UINT16 w1, w2; - SCALAR_GET_VS1(w1, i); - SCALAR_GET_VS2(w2, i); - INT32 s1 = (INT32)(INT16)w1; - INT32 s2 = (INT32)(INT16)w2; - - INT32 r = s1 * s2; - - UINT64 q = (UINT64)(UINT16)ACCUM_LL(i); - q |= (((UINT64)(UINT16)ACCUM_L(i)) << 16); - q |= (((UINT64)(UINT16)ACCUM_M(i)) << 32); - q |= (((UINT64)(UINT16)ACCUM_H(i)) << 48); - - q += (INT64)(r) << 17; - SET_ACCUM_LL((UINT16)q, i); - SET_ACCUM_L((UINT16)(q >> 16), i); - SET_ACCUM_M((UINT16)(q >> 32), i); - SET_ACCUM_H((UINT16)(q >> 48), i); - - vres[i] = SATURATE_ACCUM(i, 1, 0x8000, 0x7fff); - } - WRITEBACK_RESULT(); -} - -static void cfunc_rsp_vmacf_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vmacf_scalar(); -} -#endif - -#if USE_SIMD -// VMACU -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001001 | -// ------------------------------------------------------ -// - -inline void rsp_device::ccfunc_rsp_vmacu_simd() -{ - int op = m_rsp_state->arg0; - - __m128i loProduct, hiProduct, unpackLo, unpackHi; - __m128i vaccHigh; - __m128i vdReg, vdRegLo, vdRegHi; - - __m128i vsReg = m_xv[VS1REG]; - __m128i vtReg = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); - - __m128i vaccLow = m_accum_l; - - /* Unpack to obtain for 32-bit precision. */ - RSPZeroExtend16to32(vaccLow, &vaccLow, &vaccHigh); - - /* Begin accumulating the products. */ - unpackLo = _mm_mullo_epi16(vsReg, vtReg); - unpackHi = _mm_mulhi_epi16(vsReg, vtReg); - loProduct = _mm_unpacklo_epi16(unpackLo, unpackHi); - hiProduct = _mm_unpackhi_epi16(unpackLo, unpackHi); - loProduct = _mm_slli_epi32(loProduct, 1); - hiProduct = _mm_slli_epi32(hiProduct, 1); - - vdRegLo = _mm_srli_epi32(loProduct, 16); - vdRegHi = _mm_srli_epi32(hiProduct, 16); - vdRegLo = _mm_slli_epi32(vdRegLo, 16); - vdRegHi = _mm_slli_epi32(vdRegHi, 16); - vdRegLo = _mm_xor_si128(vdRegLo, loProduct); - vdRegHi = _mm_xor_si128(vdRegHi, hiProduct); - - vaccLow = _mm_add_epi32(vaccLow, vdRegLo); - vaccHigh = _mm_add_epi32(vaccHigh, vdRegHi); - - m_accum_l = vdReg = RSPPackLo32to16(vaccLow, vaccHigh); - - /* Multiply the MSB of sources, accumulate the product. */ - vdRegLo = _mm_unpacklo_epi16(m_accum_m, m_accum_h); - vdRegHi = _mm_unpackhi_epi16(m_accum_m, m_accum_h); - - loProduct = _mm_srai_epi32(loProduct, 16); - hiProduct = _mm_srai_epi32(hiProduct, 16); - vaccLow = _mm_srai_epi32(vaccLow, 16); - vaccHigh = _mm_srai_epi32(vaccHigh, 16); - - vaccLow = _mm_add_epi32(loProduct, vaccLow); - vaccHigh = _mm_add_epi32(hiProduct, vaccHigh); - vaccLow = _mm_add_epi32(vdRegLo, vaccLow); - vaccHigh = _mm_add_epi32(vdRegHi, vaccHigh); - - /* Clamp the accumulator and write it all out. */ - m_accum_m = RSPPackLo32to16(vaccLow, vaccHigh); - m_accum_h = RSPPackHi32to16(vaccLow, vaccHigh); -} - -static void cfunc_rsp_vmacu_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vmacu_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_vmacu_scalar() -{ - int op = m_rsp_state->arg0; - - INT16 vres[8]; - for (int i = 0; i < 8; i++) - { - UINT16 w1, w2; - SCALAR_GET_VS1(w1, i); - SCALAR_GET_VS2(w2, i); - INT32 s1 = (INT32)(INT16)w1; - INT32 s2 = (INT32)(INT16)w2; - - INT32 r1 = s1 * s2; - UINT32 r2 = (UINT16)ACCUM_L(i) + ((UINT16)(r1) * 2); - UINT32 r3 = (UINT16)ACCUM_M(i) + (UINT16)((r1 >> 16) * 2) + (UINT16)(r2 >> 16); - - SET_ACCUM_L((UINT16)(r2), i); - SET_ACCUM_M((UINT16)(r3), i); - SET_ACCUM_H(ACCUM_H(i) + (UINT16)(r3 >> 16) + (UINT16)(r1 >> 31), i); - - if ((INT16)ACCUM_H(i) < 0) - { - vres[i] = 0; - } - else - { - if (ACCUM_H(i) != 0) - { - vres[i] = (INT16)0xffff; - } - else - { - if ((INT16)ACCUM_M(i) < 0) - { - vres[i] = (INT16)0xffff; - } - else - { - vres[i] = ACCUM_M(i); - } - } - } - } - WRITEBACK_RESULT(); -} - -static void cfunc_rsp_vmacu_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vmacu_scalar(); -} -#endif - -#if USE_SIMD -// 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 - -inline void rsp_device::ccfunc_rsp_vmadl_simd() -{ - int op = m_rsp_state->arg0; - - INT16 vres[8]; - for (int i = 0; i < 8; i++) - { - UINT16 w1, w2; - VEC_GET_SCALAR_VS1(w1, i); - VEC_GET_SCALAR_VS2(w2, i); - UINT32 s1 = w1; - UINT32 s2 = w2; - - UINT32 r1 = s1 * s2; - UINT32 r2 = (UINT16)VEC_ACCUM_L(i) + (r1 >> 16); - UINT32 r3 = (UINT16)VEC_ACCUM_M(i) + (r2 >> 16); - - VEC_SET_ACCUM_L((UINT16)r2, i); - VEC_SET_ACCUM_M((UINT16)r3, i); - VEC_SET_ACCUM_H(VEC_ACCUM_H(i) + (INT16)(r3 >> 16), i); - - vres[i] = VEC_SATURATE_ACCUM(i, 0, 0x0000, 0xffff); - } - VEC_WRITEBACK_RESULT(); - - /*__m128i vaccHigh; - __m128i unpackHi, loProduct, hiProduct; - __m128i vdReg, vdRegLo, vdRegHi; - - __m128i vsReg = m_xv[VS1REG]; - __m128i vtReg = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); - - __m128i vaccLow = m_accum_l; - - // Unpack to obtain for 32-bit precision. - RSPZeroExtend16to32(vaccLow, &vaccLow, &vaccHigh); - - // Begin accumulating the products. - unpackHi = _mm_mulhi_epu16(vsReg, vtReg); - loProduct = _mm_unpacklo_epi16(unpackHi, _mm_setzero_si128()); - hiProduct = _mm_unpackhi_epi16(unpackHi, _mm_setzero_si128()); - - vaccLow = _mm_add_epi32(vaccLow, loProduct); - vaccHigh = _mm_add_epi32(vaccHigh, hiProduct); - m_accum_l = vdReg = RSPPackLo32to16(vaccLow, vaccHigh); - - // Finish accumulating whatever is left. - vdRegLo = _mm_unpacklo_epi16(m_accum_m, m_accum_h); - vdRegHi = _mm_unpackhi_epi16(m_accum_m, m_accum_h); - - vaccLow = _mm_srai_epi32(vaccLow, 16); - vaccHigh = _mm_srai_epi32(vaccHigh, 16); - vaccLow = _mm_add_epi32(vdRegLo, vaccLow); - vaccHigh = _mm_add_epi32(vdRegHi, vaccHigh); - - // Clamp the accumulator and write it all out. - m_accum_m = RSPPackLo32to16(vaccLow, vaccHigh); - m_accum_h = RSPPackHi32to16(vaccLow, vaccHigh); - m_xv[VDREG] = RSPClampLowToVal(vdReg, m_accum_m, m_accum_h);*/ -} - -static void cfunc_rsp_vmadl_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vmadl_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_vmadl_scalar() -{ - int op = m_rsp_state->arg0; - - INT16 vres[8]; - for (int i = 0; i < 8; i++) - { - UINT16 w1, w2; - SCALAR_GET_VS1(w1, i); - SCALAR_GET_VS2(w2, i); - UINT32 s1 = w1; - UINT32 s2 = w2; - - UINT32 r1 = s1 * s2; - UINT32 r2 = (UINT16)ACCUM_L(i) + (r1 >> 16); - UINT32 r3 = (UINT16)ACCUM_M(i) + (r2 >> 16); - - SET_ACCUM_L((UINT16)r2, i); - SET_ACCUM_M((UINT16)r3, i); - SET_ACCUM_H(ACCUM_H(i) + (INT16)(r3 >> 16), i); - - vres[i] = SATURATE_ACCUM(i, 0, 0x0000, 0xffff); - } - WRITEBACK_RESULT(); -} - -static void cfunc_rsp_vmadl_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vmadl_scalar(); -} -#endif - -#if USE_SIMD -// VMADM -// - -inline void rsp_device::ccfunc_rsp_vmadm_simd() -{ - int op = m_rsp_state->arg0; - - __m128i vaccLow, vaccHigh, loProduct, hiProduct; - __m128i vsRegLo, vsRegHi, vtRegLo, vtRegHi, vdRegLo, vdRegHi; - - __m128i vsReg = m_xv[VS1REG]; - __m128i vtReg = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); - - /* Unpack to obtain for 32-bit precision. */ - RSPSignExtend16to32(vsReg, &vsRegLo, &vsRegHi); - RSPZeroExtend16to32(vtReg, &vtRegLo, &vtRegHi); - RSPZeroExtend16to32(m_accum_l, &vaccLow, &vaccHigh); - - /* Begin accumulating the products. */ - loProduct = _mm_mullo_epi32(vsRegLo, vtRegLo); - hiProduct = _mm_mullo_epi32(vsRegHi, vtRegHi); - - vdRegLo = _mm_srli_epi32(loProduct, 16); - vdRegHi = _mm_srli_epi32(hiProduct, 16); - vdRegLo = _mm_slli_epi32(vdRegLo, 16); - vdRegHi = _mm_slli_epi32(vdRegHi, 16); - vdRegLo = _mm_xor_si128(vdRegLo, loProduct); - vdRegHi = _mm_xor_si128(vdRegHi, hiProduct); - vaccLow = _mm_add_epi32(vaccLow, vdRegLo); - vaccHigh = _mm_add_epi32(vaccHigh, vdRegHi); - - m_accum_l = m_xv[VDREG] = RSPPackLo32to16(vaccLow, vaccHigh); - - /* Multiply the MSB of sources, accumulate the product. */ - vdRegLo = _mm_unpacklo_epi16(m_accum_m, m_accum_h); - vdRegHi = _mm_unpackhi_epi16(m_accum_m, m_accum_h); - - loProduct = _mm_srai_epi32(loProduct, 16); - hiProduct = _mm_srai_epi32(hiProduct, 16); - vaccLow = _mm_srai_epi32(vaccLow, 16); - vaccHigh = _mm_srai_epi32(vaccHigh, 16); - - vaccLow = _mm_add_epi32(loProduct, vaccLow); - vaccHigh = _mm_add_epi32(hiProduct, vaccHigh); - vaccLow = _mm_add_epi32(vdRegLo, vaccLow); - vaccHigh = _mm_add_epi32(vdRegHi, vaccHigh); - - /* Clamp the accumulator and write it all out. */ - m_xv[VDREG] = _mm_packs_epi32(vaccLow, vaccHigh); - m_accum_m = RSPPackLo32to16(vaccLow, vaccHigh); - m_accum_h = RSPPackHi32to16(vaccLow, vaccHigh); -} - -static void cfunc_rsp_vmadm_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vmadm_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_vmadm_scalar() -{ - int op = m_rsp_state->arg0; - - INT16 vres[8]; - for (int i = 0; i < 8; i++) - { - UINT16 w1, w2; - SCALAR_GET_VS1(w1, i); - SCALAR_GET_VS2(w2, i); - UINT32 s1 = (INT32)(INT16)w1; - UINT32 s2 = (UINT16)w2; - - UINT32 r1 = s1 * s2; - UINT32 r2 = (UINT16)ACCUM_L(i) + (UINT16)(r1); - UINT32 r3 = (UINT16)ACCUM_M(i) + (r1 >> 16) + (r2 >> 16); - - SET_ACCUM_L((UINT16)r2, i); - SET_ACCUM_M((UINT16)r3, i); - SET_ACCUM_H((UINT16)ACCUM_H(i) + (UINT16)(r3 >> 16), i); - if ((INT32)(r1) < 0) - { - SET_ACCUM_H((UINT16)ACCUM_H(i) - 1, i); - } - - vres[i] = SATURATE_ACCUM(i, 1, 0x8000, 0x7fff); - } - WRITEBACK_RESULT(); -} - -static void cfunc_rsp_vmadm_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vmadm_scalar(); -} -#endif - -#if USE_SIMD -// VMADN -// - -inline void rsp_device::ccfunc_rsp_vmadn_simd() -{ - int op = m_rsp_state->arg0; - - INT16 vres[8]; - for (int i = 0; i < 8; i++) - { - UINT16 w1, w2; - VEC_GET_SCALAR_VS1(w1, i); - VEC_GET_SCALAR_VS2(w2, i); - INT32 s1 = (UINT16)w1; - INT32 s2 = (INT32)(INT16)w2; - - UINT64 q = (UINT64)VEC_ACCUM_LL(i); - q |= (((UINT64)VEC_ACCUM_L(i)) << 16); - q |= (((UINT64)VEC_ACCUM_M(i)) << 32); - q |= (((UINT64)VEC_ACCUM_H(i)) << 48); - q += (INT64)(s1*s2) << 16; - - VEC_SET_ACCUM_LL((UINT16)q, i); - VEC_SET_ACCUM_L((UINT16)(q >> 16), i); - VEC_SET_ACCUM_M((UINT16)(q >> 32), i); - VEC_SET_ACCUM_H((UINT16)(q >> 48), i); - - vres[i] = VEC_SATURATE_ACCUM(i, 0, 0x0000, 0xffff); - } - VEC_WRITEBACK_RESULT(); -} -/*INLINE void cfunc_rsp_vmadn_simd(void *param) -{ - rsp_state *rsp = (rsp_state*)param; - int op = m_rsp_state->arg0; - - __m128i vaccLow, vaccHigh, loProduct, hiProduct; - __m128i vsRegLo, vsRegHi, vtRegLo, vtRegHi, vdRegLo, vdRegHi; - - __m128i vsReg = m_xv[VS1REG]; - __m128i vtReg = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); - - vaccLow = m_accum_l; - - RSPZeroExtend16to32(vsReg, &vsRegLo, &vsRegHi); - RSPSignExtend16to32(vtReg, &vtRegLo, &vtRegHi); - RSPZeroExtend16to32(vaccLow, &vaccLow, &vaccHigh); - - // Begin accumulating the products. - loProduct = _mm_mullo_epi32(vsRegLo, vtRegLo); - hiProduct = _mm_mullo_epi32(vsRegHi, vtRegHi); - - vdRegLo = _mm_srli_epi32(loProduct, 16); - vdRegHi = _mm_srli_epi32(hiProduct, 16); - vdRegLo = _mm_slli_epi32(vdRegLo, 16); - vdRegHi = _mm_slli_epi32(vdRegHi, 16); - vdRegLo = _mm_xor_si128(vdRegLo, loProduct); - vdRegHi = _mm_xor_si128(vdRegHi, hiProduct); - - vaccLow = _mm_add_epi32(vaccLow, vdRegLo); - vaccHigh = _mm_add_epi32(vaccHigh, vdRegHi); - - m_accum_l = RSPPackLo32to16(vaccLow, vaccHigh); - - // Multiply the MSB of sources, accumulate the product. - vdRegLo = _mm_unpacklo_epi16(m_accum_m, m_accum_h); - vdRegHi = _mm_unpackhi_epi16(m_accum_m, m_accum_h); - - loProduct = _mm_srai_epi32(loProduct, 16); - hiProduct = _mm_srai_epi32(hiProduct, 16); - vaccLow = _mm_srai_epi32(vaccLow, 16); - vaccHigh = _mm_srai_epi32(vaccHigh, 16); - - vaccLow = _mm_add_epi32(loProduct, vaccLow); - vaccHigh = _mm_add_epi32(hiProduct, vaccHigh); - vaccLow = _mm_add_epi32(vdRegLo, vaccLow); - vaccHigh = _mm_add_epi32(vdRegHi, vaccHigh); - - // Clamp the accumulator and write it all out. - m_accum_m = RSPPackLo32to16(vaccLow, vaccHigh); - m_accum_h = RSPPackHi32to16(vaccLow, vaccHigh); - m_xv[VDREG] = RSPClampLowToVal(m_accum_l, m_accum_m, m_accum_h); -}*/ - -static void cfunc_rsp_vmadn_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vmadn_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_vmadn_scalar() -{ - int op = m_rsp_state->arg0; - - INT16 vres[8]; - for (int i = 0; i < 8; i++) - { - UINT16 w1, w2; - SCALAR_GET_VS1(w1, i); - SCALAR_GET_VS2(w2, i); - INT32 s1 = (UINT16)w1; - INT32 s2 = (INT32)(INT16)w2; - - UINT64 q = (UINT64)ACCUM_LL(i); - q |= (((UINT64)ACCUM_L(i)) << 16); - q |= (((UINT64)ACCUM_M(i)) << 32); - q |= (((UINT64)ACCUM_H(i)) << 48); - q += (INT64)(s1*s2) << 16; - - SET_ACCUM_LL((UINT16)q, i); - SET_ACCUM_L((UINT16)(q >> 16), i); - SET_ACCUM_M((UINT16)(q >> 32), i); - SET_ACCUM_H((UINT16)(q >> 48), i); - - vres[i] = SATURATE_ACCUM(i, 0, 0x0000, 0xffff); - } - WRITEBACK_RESULT(); -} - -static void cfunc_rsp_vmadn_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vmadn_scalar(); -} -#endif - -#if USE_SIMD -// 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 - -inline void rsp_device::ccfunc_rsp_vmadh_simd() -{ - int op = m_rsp_state->arg0; - - __m128i vsReg = m_xv[VS1REG]; - __m128i vtReg = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); - - /* Unpack to obtain for 32-bit precision. */ - __m128i vaccLow = _mm_unpacklo_epi16(m_accum_m, m_accum_h); - __m128i vaccHigh = _mm_unpackhi_epi16(m_accum_m, m_accum_h); - - /* Multiply the sources, accumulate the product. */ - __m128i unpackLo = _mm_mullo_epi16(vsReg, vtReg); - __m128i unpackHi = _mm_mulhi_epi16(vsReg, vtReg); - __m128i loProduct = _mm_unpacklo_epi16(unpackLo, unpackHi); - __m128i hiProduct = _mm_unpackhi_epi16(unpackLo, unpackHi); - vaccLow = _mm_add_epi32(vaccLow, loProduct); - vaccHigh = _mm_add_epi32(vaccHigh, hiProduct); - - /* Pack the accumulator and result back up. */ - m_xv[VDREG] = _mm_packs_epi32(vaccLow, vaccHigh); - m_accum_m = RSPPackLo32to16(vaccLow, vaccHigh); - m_accum_h = RSPPackHi32to16(vaccLow, vaccHigh); -} - -static void cfunc_rsp_vmadh_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vmadh_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_vmadh_scalar() -{ - int op = m_rsp_state->arg0; - - INT16 vres[8]; - for (int i = 0; i < 8; i++) - { - INT16 w1, w2; - SCALAR_GET_VS1(w1, i); - SCALAR_GET_VS2(w2, i); - INT32 s1 = (INT32)(INT16)w1; - INT32 s2 = (INT32)(INT16)w2; - - INT32 accum = (UINT32)(UINT16)ACCUM_M(i); - accum |= ((UINT32)((UINT16)ACCUM_H(i))) << 16; - accum += s1 * s2; - - SET_ACCUM_H((UINT16)(accum >> 16), i); - SET_ACCUM_M((UINT16)accum, i); - - vres[i] = SATURATE_ACCUM1(i, 0x8000, 0x7fff); - } - WRITEBACK_RESULT(); -} - -static void cfunc_rsp_vmadh_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vmadh_scalar(); -} -#endif - -#if USE_SIMD -// 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 - -inline void rsp_device::ccfunc_rsp_vadd_simd() -{ - int op = m_rsp_state->arg0; - - __m128i shuffled = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); - __m128i carry = _mm_and_si128(m_xvflag[CARRY], vec_flagmask); - m_accum_l = _mm_add_epi16(_mm_add_epi16(m_xv[VS1REG], shuffled), carry); - - __m128i addvec = _mm_adds_epi16(m_xv[VS1REG], shuffled); - - carry = _mm_and_si128(carry, _mm_xor_si128(_mm_cmpeq_epi16(addvec, vec_32767), vec_neg1)); - carry = _mm_and_si128(carry, _mm_xor_si128(_mm_cmpeq_epi16(addvec, vec_n32768), vec_neg1)); - - m_xv[VDREG] = _mm_add_epi16(addvec, carry); - - m_xvflag[ZERO] = vec_zero; - m_xvflag[CARRY] = vec_zero; -} - -static void cfunc_rsp_vadd_simd(void *param) -{ - ((rsp_Device *)param)->ccfunc_rsp_vadd_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_vadd_scalar() -{ - int op = m_rsp_state->arg0; - - INT16 vres[8] = { 0 }; - for (int i = 0; i < 8; i++) - { - INT16 w1, w2; - SCALAR_GET_VS1(w1, i); - SCALAR_GET_VS2(w2, i); - INT32 s1 = (INT32)(INT16)w1; - INT32 s2 = (INT32)(INT16)w2; - INT32 r = s1 + s2 + (((CARRY_FLAG(i)) != 0) ? 1 : 0); - - SET_ACCUM_L((INT16)(r), i); - - if (r > 32767) r = 32767; - if (r < -32768) r = -32768; - vres[i] = (INT16)(r); - } - CLEAR_ZERO_FLAGS(); - CLEAR_CARRY_FLAGS(); - WRITEBACK_RESULT(); -} - -static void cfunc_rsp_vadd_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vadd_scalar(); -} -#endif - -#if USE_SIMD -// 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 - -inline void rsp_device::ccfunc_rsp_vsub_simd() -{ - int op = m_rsp_state->arg0; - - __m128i shuffled = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); - __m128i carry = _mm_and_si128(m_xvflag[CARRY], vec_flagmask); - __m128i unsat = _mm_sub_epi16(m_xv[VS1REG], shuffled); - - __m128i vs2neg = _mm_cmplt_epi16(shuffled, vec_zero); - __m128i vs2pos = _mm_cmpeq_epi16(vs2neg, vec_zero); - - __m128i saturated = _mm_subs_epi16(m_xv[VS1REG], shuffled); - __m128i carry_mask = _mm_cmpeq_epi16(unsat, saturated); - carry_mask = _mm_and_si128(vs2neg, carry_mask); - - vs2neg = _mm_and_si128(carry_mask, carry); - vs2pos = _mm_and_si128(vs2pos, carry); - __m128i dest_carry = _mm_or_si128(vs2neg, vs2pos); - m_xv[VDREG] = _mm_subs_epi16(saturated, dest_carry); - - m_accum_l = _mm_sub_epi16(unsat, carry); - - m_xvflag[ZERO] = _mm_setzero_si128(); - m_xvflag[CARRY] = _mm_setzero_si128(); -} - -static void cfunc_rsp_vsub_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vsub_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_vsub_scalar() -{ - int op = m_rsp_state->arg0; - - INT16 vres[8]; - for (int i = 0; i < 8; i++) - { - INT16 w1, w2; - SCALAR_GET_VS1(w1, i); - SCALAR_GET_VS2(w2, i); - INT32 s1 = (INT32)(INT16)w1; - INT32 s2 = (INT32)(INT16)w2; - INT32 r = s1 - s2 - (((CARRY_FLAG(i)) != 0) ? 1 : 0); - - SET_ACCUM_L((INT16)(r), i); - - if (r > 32767) r = 32767; - if (r < -32768) r = -32768; - - vres[i] = (INT16)(r); - } - CLEAR_ZERO_FLAGS(); - CLEAR_CARRY_FLAGS(); - WRITEBACK_RESULT(); -} - -static void cfunc_rsp_vsub_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vsub_scalar(); -} -#endif - -#if USE_SIMD -// 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 - -inline void rsp_device::ccfunc_rsp_vabs_simd() -{ - int op = m_rsp_state->arg0; - - __m128i shuf2 = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); - __m128i negs2 = _mm_sub_epi16(_mm_setzero_si128(), shuf2); - __m128i s2_n32768 = _mm_cmpeq_epi16(shuf2, vec_n32768); - __m128i s1_lz = _mm_cmplt_epi16(m_xv[VS1REG], _mm_setzero_si128()); - - __m128i result_gz = _mm_and_si128(shuf2, _mm_cmpgt_epi16(m_xv[VS1REG], _mm_setzero_si128())); - __m128i result_n32768 = _mm_and_si128(s1_lz, _mm_and_si128(vec_32767, s2_n32768)); - __m128i result_negs2 = _mm_and_si128(s1_lz, _mm_and_si128(negs2, _mm_xor_si128(s2_n32768, vec_neg1))); - m_xv[VDREG] = m_accum_l = _mm_or_si128(result_gz, _mm_or_si128(result_n32768, result_negs2)); -} - -static void cfunc_rsp_vabs_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vabs_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_vabs_scalar() -{ - int op = m_rsp_state->arg0; - - INT16 vres[8]; - for (int i = 0; i < 8; i++) - { - INT16 s1, s2; - SCALAR_GET_VS1(s1, i); - SCALAR_GET_VS2(s2, 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; - } - - SET_ACCUM_L(vres[i], i); - } - WRITEBACK_RESULT(); -} - -static void cfunc_rsp_vabs_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vabs_scalar(); -} -#endif - -#if USE_SIMD -// 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 - -inline void rsp_device::ccfunc_rsp_vaddc_simd() -{ - int op = m_rsp_state->arg0; - - VEC_CLEAR_ZERO_FLAGS(); - VEC_CLEAR_CARRY_FLAGS(); - - __m128i shuf2 = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); - __m128i vec7531 = _mm_and_si128(m_xv[VS1REG], vec_lomask); - __m128i vec6420 = _mm_srli_epi32(m_xv[VS1REG], 16); - __m128i shuf7531 = _mm_and_si128(shuf2, vec_lomask); - __m128i shuf6420 = _mm_srli_epi32(shuf2, 16); - __m128i sum7531 = _mm_add_epi32(vec7531, shuf7531); - __m128i sum6420 = _mm_add_epi32(vec6420, shuf6420); - - __m128i over7531 = _mm_and_si128(_mm_xor_si128(_mm_cmpeq_epi16(sum7531, _mm_setzero_si128()), vec_neg1), vec_himask); - __m128i over6420 = _mm_and_si128(_mm_xor_si128(_mm_cmpeq_epi16(sum6420, _mm_setzero_si128()), vec_neg1), vec_himask); - - sum7531 = _mm_and_si128(sum7531, vec_lomask); - sum6420 = _mm_and_si128(sum6420, vec_lomask); - - m_xvflag[CARRY] = _mm_or_si128(over6420, _mm_srli_epi32(over7531, 16)); - m_accum_l = m_xv[VDREG] = _mm_or_si128(_mm_slli_epi32(sum6420, 16), sum7531); -} - -static void cfunc_rsp_vaddc_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vaddc_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_vaddc_scalar() -{ - int op = m_rsp_state->arg0; - - CLEAR_ZERO_FLAGS(); - CLEAR_CARRY_FLAGS(); - - INT16 vres[8] = { 0 }; - for (int i = 0; i < 8; i++) - { - INT16 w1, w2; - SCALAR_GET_VS1(w1, i); - SCALAR_GET_VS2(w2, i); - INT32 s1 = (UINT32)(UINT16)w1; - INT32 s2 = (UINT32)(UINT16)w2; - INT32 r = s1 + s2; - - vres[i] = (INT16)(r); - SET_ACCUM_L((INT16)r, i); - - if (r & 0xffff0000) - { - SET_CARRY_FLAG(i); - } - } - WRITEBACK_RESULT(); -} - -static void cfunc_rsp_vaddc_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vaddc_scalar(); -} -#endif - -#if USE_SIMD -// 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 - -inline void rsp_device::ccfunc_rsp_vsubc_simd() -{ - int op = m_rsp_state->arg0; - - VEC_CLEAR_ZERO_FLAGS(); - VEC_CLEAR_CARRY_FLAGS(); - - __m128i shuf2 = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); - __m128i vec7531 = _mm_and_si128(m_xv[VS1REG], vec_lomask); - __m128i vec6420 = _mm_srli_epi32(m_xv[VS1REG], 16); - __m128i shuf7531 = _mm_and_si128(shuf2, vec_lomask); - __m128i shuf6420 = _mm_srli_epi32(shuf2, 16); - __m128i sum7531 = _mm_sub_epi32(vec7531, shuf7531); - __m128i sum6420 = _mm_sub_epi32(vec6420, shuf6420); - - __m128i over7531 = _mm_and_si128(_mm_xor_si128(_mm_cmpeq_epi16(sum7531, _mm_setzero_si128()), vec_neg1), vec_himask); - __m128i over6420 = _mm_and_si128(_mm_xor_si128(_mm_cmpeq_epi16(sum6420, _mm_setzero_si128()), vec_neg1), vec_himask); - sum7531 = _mm_and_si128(sum7531, vec_lomask); - sum6420 = _mm_and_si128(sum6420, vec_lomask); - __m128i zero7531 = _mm_and_si128(_mm_xor_si128(_mm_cmpeq_epi16(sum7531, _mm_setzero_si128()), vec_neg1), vec_lomask); - __m128i zero6420 = _mm_and_si128(_mm_xor_si128(_mm_cmpeq_epi16(sum6420, _mm_setzero_si128()), vec_neg1), vec_lomask); - - m_xvflag[CARRY] = _mm_or_si128(over6420, _mm_srli_epi32(over7531, 16)); - m_xvflag[ZERO] = _mm_or_si128(_mm_slli_epi32(zero6420, 16), zero7531); - - m_accum_l = m_xv[VDREG] = _mm_or_si128(_mm_slli_epi32(sum6420, 16), sum7531); -} - -static void cfunc_rsp_vsubc_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vsubc_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_vsubc_scalar() -{ - int op = m_rsp_state->arg0; - - CLEAR_ZERO_FLAGS(); - CLEAR_CARRY_FLAGS(); - - INT16 vres[8]; - for (int i = 0; i < 8; i++) - { - INT16 w1, w2; - SCALAR_GET_VS1(w1, i); - SCALAR_GET_VS2(w2, i); - INT32 s1 = (UINT32)(UINT16)w1; - INT32 s2 = (UINT32)(UINT16)w2; - INT32 r = s1 - s2; - - vres[i] = (INT16)(r); - SET_ACCUM_L((UINT16)r, i); - - if ((UINT16)(r) != 0) - { - SET_ZERO_FLAG(i); - } - if (r & 0xffff0000) - { - SET_CARRY_FLAG(i); - } - } - WRITEBACK_RESULT(); -} - -static void cfunc_rsp_vsubc_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vsubc_scalar(); -} -#endif - -// VADDB -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 010110 | -// ------------------------------------------------------ -// -// Adds two vector registers bytewise with rounding -inline void rsp_device::ccfunc_rsp_vaddb_scalar() -{ - const int op = m_rsp_state->arg0; - const int round = (EL == 0) ? 0 : (1 << (EL - 1)); - - INT16 vres[8]; - for (int i = 0; i < 8; i++) - { - UINT16 w1, w2; - SCALAR_GET_VS1(w1, i); - SCALAR_GET_VS2(w2, i); - - UINT8 hb1 = w1 >> 8; - UINT8 lb1 = w1 & 0xff; - UINT8 hb2 = w2 >> 8; - UINT8 lb2 = w2 & 0xff; - - UINT16 hs = hb1 + hb2 + round; - UINT16 ls = lb1 + lb2 + round; - - SET_ACCUM_L((hs << 8) | ls, i); - - hs >>= EL; - if (hs > 255) - { - hs = 255; - } - /*else if (hs < 0) - { - hs = 0; - }*/ - - ls >>= EL; - if (ls > 255) - { - ls = 255; - } - /*else if (ls < 0) - { - ls = 0; - }*/ - - vres[i] = 0; // VD writeback disabled on production hardware - // vres[i] = (hs << 8) | ls; - } - WRITEBACK_RESULT(); -} - -static void cfunc_rsp_vaddb_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vaddb_scalar(); -} - -#if USE_SIMD -// 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 - -inline void rsp_device::ccfunc_rsp_vsaw_simd() -{ - int op = m_rsp_state->arg0; - - switch (EL) - { - case 0x08: // VSAWH - { - m_xv[VDREG] = m_accum_h; - break; - } - case 0x09: // VSAWM - { - m_xv[VDREG] = m_accum_m; - break; - } - case 0x0a: // VSAWL - { - m_xv[VDREG] = m_accum_l; - break; - } - default: // Unsupported, writes 0 to VD - { - - } - } -} - -static void cfunc_rsp_vsaw_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vsaw_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_vsaw_scalar() -{ - int op = m_rsp_state->arg0; - - 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; - } - } - } -} - -static void cfunc_rsp_vsaw_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vsaw_scalar(); -} -#endif - -#if USE_SIMD -// 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 - -inline void rsp_device::ccfunc_rsp_vlt_simd() -{ - int op = m_rsp_state->arg0; - - m_xvflag[COMPARE] = m_xvflag[CLIP2] = _mm_setzero_si128(); - - __m128i shuf = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); - __m128i zc_mask = _mm_and_si128(m_xvflag[ZERO], m_xvflag[CARRY]); - __m128i lt_mask = _mm_cmplt_epi16(m_xv[VS1REG], shuf); - __m128i eq_mask = _mm_and_si128(_mm_cmpeq_epi16(m_xv[VS1REG], shuf), zc_mask); - - m_xvflag[COMPARE] = _mm_or_si128(lt_mask, eq_mask); - - __m128i result = _mm_and_si128(m_xv[VS1REG], m_xvflag[COMPARE]); - m_accum_l = m_xv[VDREG] = _mm_or_si128(result, _mm_and_si128(shuf, _mm_xor_si128(m_xvflag[COMPARE], vec_neg1))); - - m_xvflag[ZERO] = m_xvflag[CARRY] = _mm_setzero_si128(); -} - -static void void cfunc_rsp_vlt_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vlt_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_vlt_scalar() -{ - int op = m_rsp_state->arg0; - - CLEAR_COMPARE_FLAGS(); - CLEAR_CLIP2_FLAGS(); - - INT16 vres[8]; - for (int i = 0; i < 8; i++) - { - INT16 s1, s2; - SCALAR_GET_VS1(s1, i); - SCALAR_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) - { - vres[i] = s1; - } - else - { - vres[i] = s2; - } - - SET_ACCUM_L(vres[i], i); - } - - CLEAR_ZERO_FLAGS(); - CLEAR_CARRY_FLAGS(); - WRITEBACK_RESULT(); -} - -static void cfunc_rsp_vlt_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vlt_scalar(); -} -#endif - -#if USE_SIMD -// 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 - -inline void rsp_device::ccfunc_rsp_veq_simd() -{ - int op = m_rsp_state->arg0; - - m_xvflag[COMPARE] = m_xvflag[CLIP2] = _mm_setzero_si128(); - - __m128i shuf = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); - __m128i zero_mask = _mm_cmpeq_epi16(m_xvflag[ZERO], _mm_setzero_si128()); - __m128i eq_mask = _mm_cmpeq_epi16(m_xv[VS1REG], shuf); - - m_xvflag[COMPARE] = _mm_and_si128(zero_mask, eq_mask); - - __m128i result = _mm_and_si128(m_xv[VS1REG], m_xvflag[COMPARE]); - m_accum_l = m_xv[VDREG] = _mm_or_si128(result, _mm_and_si128(shuf, _mm_xor_si128(m_xvflag[COMPARE], vec_neg1))); - - m_xvflag[ZERO] = m_xvflag[CARRY] = _mm_setzero_si128(); -} - -static void cfunc_rsp_veq_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_veq_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_veq_scalar() -{ - int op = m_rsp_state->arg0; - - CLEAR_COMPARE_FLAGS(); - CLEAR_CLIP2_FLAGS(); - - INT16 vres[8]; - for (int i = 0; i < 8; i++) - { - INT16 s1, s2; - SCALAR_GET_VS1(s1, i); - SCALAR_GET_VS2(s2, i); - - if ((s1 == s2) && ZERO_FLAG(i) == 0) - { - SET_COMPARE_FLAG(i); - vres[i] = s1; - } - else - { - vres[i] = s2; - } - - SET_ACCUM_L(vres[i], i); - } - - CLEAR_ZERO_FLAGS(); - CLEAR_CARRY_FLAGS(); - WRITEBACK_RESULT(); -} - -static void cfunc_rsp_veq_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_veq_scalar(); -} -#endif - -#if USE_SIMD -// 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 - -inline void rsp_device::ccfunc_rsp_vne_simd() -{ - int op = m_rsp_state->arg0; - - m_xvflag[COMPARE] = m_xvflag[CLIP2] = _mm_setzero_si128(); - - __m128i shuf = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); - __m128i neq_mask = _mm_xor_si128(_mm_cmpeq_epi16(m_xv[VS1REG], shuf), vec_neg1); - - m_xvflag[COMPARE] = _mm_or_si128(m_xvflag[ZERO], neq_mask); - - __m128i result = _mm_and_si128(m_xv[VS1REG], m_xvflag[COMPARE]); - m_accum_l = m_xv[VDREG] = _mm_or_si128(result, _mm_and_si128(shuf, _mm_xor_si128(m_xvflag[COMPARE], vec_neg1))); - - m_xvflag[ZERO] = m_xvflag[CARRY] = _mm_setzero_si128(); -} - -static void cfunc_rsp_vne_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vne_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_vne_scalar() -{ - int op = m_rsp_state->arg0; - - CLEAR_COMPARE_FLAGS(); - CLEAR_CLIP2_FLAGS(); - - INT16 vres[8]; - for (int i = 0; i < 8; i++) - { - INT16 s1, s2; - SCALAR_GET_VS1(s1, i); - SCALAR_GET_VS2(s2, i); - - if (s1 != s2 || ZERO_FLAG(i) != 0) - { - SET_COMPARE_FLAG(i); - vres[i] = s1; - } - else - { - vres[i] = s2; - } - - SET_ACCUM_L(vres[i], i); - } - - CLEAR_ZERO_FLAGS(); - CLEAR_CARRY_FLAGS(); - WRITEBACK_RESULT(); -} - -static void cfunc_rsp_vne_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vne_scalar(); -} -#endif - -#if USE_SIMD -// 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 - -inline void rsp_device::ccfunc_rsp_vge_simd() -{ - int op = m_rsp_state->arg0; - - m_xvflag[COMPARE] = m_xvflag[CLIP2] = _mm_setzero_si128(); - - __m128i shuf = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); - __m128i zero_mask = _mm_cmpeq_epi16(m_xvflag[ZERO], _mm_setzero_si128()); - __m128i carry_mask = _mm_cmpeq_epi16(m_xvflag[CARRY], _mm_setzero_si128()); - __m128i flag_mask = _mm_or_si128(zero_mask, carry_mask); - __m128i eq_mask = _mm_and_si128(_mm_cmpeq_epi16(m_xv[VS1REG], shuf), flag_mask); - __m128i gt_mask = _mm_cmpgt_epi16(m_xv[VS1REG], shuf); - m_xvflag[COMPARE] = _mm_or_si128(eq_mask, gt_mask); - - __m128i result = _mm_and_si128(m_xv[VS1REG], m_xvflag[COMPARE]); - m_accum_l = m_xv[VDREG] = _mm_or_si128(result, _mm_and_si128(shuf, _mm_xor_si128(m_xvflag[COMPARE], vec_neg1))); - - m_xvflag[ZERO] = m_xvflag[CARRY] = _mm_setzero_si128(); -} - -static void cfunc_rsp_vge_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vge_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_vge_scalar() -{ - int op = m_rsp_state->arg0; - - CLEAR_COMPARE_FLAGS(); - CLEAR_CLIP2_FLAGS(); - - INT16 vres[8]; - for (int i = 0; i < 8; i++) - { - INT16 s1, s2; - SCALAR_GET_VS1(s1, i); - SCALAR_GET_VS2(s2, i); - if ((s1 == s2 && (ZERO_FLAG(i) == 0 || CARRY_FLAG(i) == 0)) || s1 > s2) - { - SET_COMPARE_FLAG(i); - vres[i] = s1; - } - else - { - vres[i] = s2; - } - - SET_ACCUM_L(vres[i], i); - } - - CLEAR_ZERO_FLAGS(); - CLEAR_CARRY_FLAGS(); - WRITEBACK_RESULT(); -} - -static void cfunc_rsp_vge_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vge_scalar(); -} -#endif - -#if USE_SIMD -// VCL -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100100 | -// ------------------------------------------------------ -// -// Vector clip low - -inline void rsp_device::ccfunc_rsp_vcl_simd() -{ - int op = m_rsp_state->arg0; - INT16 vres[8]; - - for (int i = 0; i < 8; i++) - { - INT16 s1, s2; - VEC_GET_SCALAR_VS1(s1, i); - VEC_GET_SCALAR_VS2(s2, i); - - if (VEC_CARRY_FLAG(i) != 0) - { - if (VEC_ZERO_FLAG(i) != 0) - { - if (VEC_COMPARE_FLAG(i) != 0) - { - VEC_SET_ACCUM_L(-(UINT16)s2, i); - } - else - { - VEC_SET_ACCUM_L(s1, i); - } - } - else - { - if (VEC_CLIP1_FLAG(i) != 0) - { - if (((UINT32)(UINT16)(s1) + (UINT32)(UINT16)(s2)) > 0x10000) - { - VEC_SET_ACCUM_L(s1, i); - VEC_CLEAR_COMPARE_FLAG(i); - } - else - { - VEC_SET_ACCUM_L(-((UINT16)s2), i); - VEC_SET_COMPARE_FLAG(i); - } - } - else - { - if (((UINT32)(UINT16)(s1) + (UINT32)(UINT16)(s2)) != 0) - { - VEC_SET_ACCUM_L(s1, i); - VEC_CLEAR_COMPARE_FLAG(i); - } - else - { - VEC_SET_ACCUM_L(-((UINT16)s2), i); - VEC_SET_COMPARE_FLAG(i); - } - } - } - } - else - { - if (VEC_ZERO_FLAG(i) != 0) - { - if (VEC_CLIP2_FLAG(i) != 0) - { - VEC_SET_ACCUM_L(s2, i); - } - else - { - VEC_SET_ACCUM_L(s1, i); - } - } - else - { - if (((INT32)(UINT16)s1 - (INT32)(UINT16)s2) >= 0) - { - VEC_SET_ACCUM_L(s2, i); - VEC_SET_CLIP2_FLAG(i); - } - else - { - VEC_SET_ACCUM_L(s1, i); - VEC_CLEAR_CLIP2_FLAG(i); - } - } - } - vres[i] = VEC_ACCUM_L(i); - } - VEC_CLEAR_ZERO_FLAGS(); - VEC_CLEAR_CARRY_FLAGS(); - VEC_CLEAR_CLIP1_FLAGS(); - VEC_WRITEBACK_RESULT(); -} - -static void cfunc_rsp_vcl_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vcl_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_vcl_scalar() -{ - int op = m_rsp_state->arg0; - INT16 vres[8]; - - for (int i = 0; i < 8; i++) - { - INT16 s1, s2; - SCALAR_GET_VS1(s1, i); - SCALAR_GET_VS2(s2, i); - - if (CARRY_FLAG(i) != 0) - { - if (ZERO_FLAG(i) != 0) - { - if (COMPARE_FLAG(i) != 0) - { - SET_ACCUM_L(-(UINT16)s2, i); - } - else - { - SET_ACCUM_L(s1, i); - } - } - else - { - if (CLIP1_FLAG(i) != 0) - { - if (((UINT32)(UINT16)(s1) + (UINT32)(UINT16)(s2)) > 0x10000) - { - SET_ACCUM_L(s1, i); - CLEAR_COMPARE_FLAG(i); - } - else - { - SET_ACCUM_L(-((UINT16)s2), i); - SET_COMPARE_FLAG(i); - } - } - else - { - if (((UINT32)(UINT16)(s1) + (UINT32)(UINT16)(s2)) != 0) - { - SET_ACCUM_L(s1, i); - CLEAR_COMPARE_FLAG(i); - } - else - { - SET_ACCUM_L(-((UINT16)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)(UINT16)s1 - (INT32)(UINT16)s2) >= 0) - { - SET_ACCUM_L(s2, i); - SET_CLIP2_FLAG(i); - } - else - { - SET_ACCUM_L(s1, i); - CLEAR_CLIP2_FLAG(i); - } - } - } - vres[i] = ACCUM_L(i); - } - CLEAR_ZERO_FLAGS(); - CLEAR_CARRY_FLAGS(); - CLEAR_CLIP1_FLAGS(); - WRITEBACK_RESULT(); -} - -static void cfunc_rsp_vcl_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vcl_scalar(); -} -#endif - -#if USE_SIMD -// VCH -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100101 | -// ------------------------------------------------------ -// -// Vector clip high - -inline void rsp_device::ccfunc_rsp_vch_simd() -{ - int op = m_rsp_state->arg0; - - VEC_CLEAR_CARRY_FLAGS(); - VEC_CLEAR_COMPARE_FLAGS(); - VEC_CLEAR_CLIP1_FLAGS(); - VEC_CLEAR_ZERO_FLAGS(); - VEC_CLEAR_CLIP2_FLAGS(); - -#if 0 - // Compare flag - // flag[1] bit [0- 7] set if (s1 ^ s2) < 0 && (s1 + s2) <= 0) - // flag[1] bit [0- 7] set if (s1 ^ s2) >= 0 && (s2 < 0) - - // flag[1] bit [8-15] set if (s1 ^ s2) < 0 && (s2 < 0) - // flag[1] bit [8-15] set if (s1 ^ s2) >= 0 && (s1 - s2) >= 0 - - // Carry flag - // flag[0] bit [0- 7] set if (s1 ^ s2) < 0 - - // Zero flag - // flag[0] bit [8-15] set if (s1 ^ s2) < 0 && (s1 + s2) != 0 && (s1 != ~s2) - // flag[0] bit [8-15] set if (s1 ^ s2) >= 0 && (s1 - s2) != 0 && (s1 != ~s2) - - // flag[2] bit [0- 7] set if (s1 ^ s2) < 0 && (s1 + s2) == -1 - - // accum set to -s2 if (s1 ^ s2) < 0 && (s1 + s2) <= 0) - // accum set to -s2 if (s1 ^ s2) >= 0 && (s1 - s2) >= 0 - - // accum set to s1 if (s1 ^ s2) < 0 && (s1 + s2) > 0) - // accum set to s1 if (s1 ^ s2) >= 0 && (s1 - s2) < 0 - - __m128i shuf = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); - __m128i s1_xor_s2 = _mm_xor_si128(m_xv[VS1REG], shuf); - __m128i s1_plus_s2 = _mm_add_epi16(m_xv[VS1REG], shuf); - __m128i s1_sub_s2 = _mm_sub_epi16(m_xv[VS1REG], shuf); - __m128i s2_neg = _mm_xor_si128(shuf, vec_neg1); - - __m128i s2_lz = _mm_cmplt_epi16(shuf, _mm_setzero_si128()); - __m128i s1s2_xor_lz = _mm_cmplt_epi16(s1_xor_s2, _mm_setzero_si128()); - __m128i s1s2_xor_gez = _mm_xor_si128(s1s2_xor_lz, vec_neg1); - __m128i s1s2_plus_nz = _mm_xor_si128(_mm_cmpeq_epi16(s1_plus_s2, _mm_setzero_si128()), vec_neg1); - __m128i s1s2_plus_gz = _mm_cmpgt_epi16(s1_plus_s2, _mm_setzero_si128()); - __m128i s1s2_plus_lez = _mm_xor_si128(s1s2_plus_gz, vec_neg1); - __m128i s1s2_plus_n1 = _mm_cmpeq_epi16(s1_plus_s2, vec_neg1); - __m128i s1s2_sub_nz = _mm_xor_si128(_mm_cmpeq_epi16(s1_sub_s2, _mm_setzero_si128()), vec_neg1); - __m128i s1s2_sub_lz = _mm_cmplt_epi16(s1_sub_s2, _mm_setzero_si128()); - __m128i s1s2_sub_gez = _mm_xor_si128(s1s2_sub_lz, vec_neg1); - __m128i s1_nens2 = _mm_xor_si128(_mm_cmpeq_epi16(m_xv[VS1REG], s2_neg), vec_neg1); - - __m128i ext_mask = _mm_and_si128(_mm_and_si128(s1s2_xor_lz, s1s2_plus_n1), vec_flagmask); - m_flag[2] |= _mm_extract_epi16(ext_mask, 0) << 0; - m_flag[2] |= _mm_extract_epi16(ext_mask, 1) << 1; - m_flag[2] |= _mm_extract_epi16(ext_mask, 2) << 2; - m_flag[2] |= _mm_extract_epi16(ext_mask, 3) << 3; - m_flag[2] |= _mm_extract_epi16(ext_mask, 4) << 4; - m_flag[2] |= _mm_extract_epi16(ext_mask, 5) << 5; - m_flag[2] |= _mm_extract_epi16(ext_mask, 6) << 6; - m_flag[2] |= _mm_extract_epi16(ext_mask, 7) << 7; - - __m128i carry_mask = _mm_and_si128(s1s2_xor_lz, vec_flagmask); - m_flag[0] |= _mm_extract_epi16(carry_mask, 0) << 0; - m_flag[0] |= _mm_extract_epi16(carry_mask, 1) << 1; - m_flag[0] |= _mm_extract_epi16(carry_mask, 2) << 2; - m_flag[0] |= _mm_extract_epi16(carry_mask, 3) << 3; - m_flag[0] |= _mm_extract_epi16(carry_mask, 4) << 4; - m_flag[0] |= _mm_extract_epi16(carry_mask, 5) << 5; - m_flag[0] |= _mm_extract_epi16(carry_mask, 6) << 6; - m_flag[0] |= _mm_extract_epi16(carry_mask, 7) << 7; - - __m128i z0_mask = _mm_and_si128(_mm_and_si128(s1s2_xor_gez, s1s2_sub_nz), s1_nens2); - __m128i z1_mask = _mm_and_si128(_mm_and_si128(s1s2_xor_lz, s1s2_plus_nz), s1_nens2); - __m128i z_mask = _mm_and_si128(_mm_or_si128(z0_mask, z1_mask), vec_flagmask); - z_mask = _mm_and_si128(_mm_or_si128(z_mask, _mm_srli_epi32(z_mask, 15)), vec_shiftmask2); - z_mask = _mm_and_si128(_mm_or_si128(z_mask, _mm_srli_epi64(z_mask, 30)), vec_shiftmask4); - z_mask = _mm_or_si128(z_mask, _mm_srli_si128(z_mask, 7)); - z_mask = _mm_or_si128(z_mask, _mm_srli_epi16(z_mask, 4)); - m_flag[0] |= (_mm_extract_epi16(z_mask, 0) << 8) & 0x00ff00; - - __m128i f0_mask = _mm_and_si128(_mm_or_si128(_mm_and_si128(s1s2_xor_gez, s2_lz), _mm_and_si128(s1s2_xor_lz, s1s2_plus_lez)), vec_flagmask); - __m128i f8_mask = _mm_and_si128(_mm_or_si128(_mm_and_si128(s1s2_xor_gez, s1s2_sub_gez), _mm_and_si128(s1s2_xor_lz, s2_lz)), vec_flagmask); - f0_mask = _mm_and_si128(f0_mask, vec_flagmask); - f8_mask = _mm_and_si128(f8_mask, vec_flagmask); - m_flag[1] |= _mm_extract_epi16(f0_mask, 0) << 0; - m_flag[1] |= _mm_extract_epi16(f0_mask, 1) << 1; - m_flag[1] |= _mm_extract_epi16(f0_mask, 2) << 2; - m_flag[1] |= _mm_extract_epi16(f0_mask, 3) << 3; - m_flag[1] |= _mm_extract_epi16(f0_mask, 4) << 4; - m_flag[1] |= _mm_extract_epi16(f0_mask, 5) << 5; - m_flag[1] |= _mm_extract_epi16(f0_mask, 6) << 6; - m_flag[1] |= _mm_extract_epi16(f0_mask, 7) << 7; - - m_flag[1] |= _mm_extract_epi16(f8_mask, 0) << 8; - m_flag[1] |= _mm_extract_epi16(f8_mask, 1) << 9; - m_flag[1] |= _mm_extract_epi16(f8_mask, 2) << 10; - m_flag[1] |= _mm_extract_epi16(f8_mask, 3) << 11; - m_flag[1] |= _mm_extract_epi16(f8_mask, 4) << 12; - m_flag[1] |= _mm_extract_epi16(f8_mask, 5) << 13; - m_flag[1] |= _mm_extract_epi16(f8_mask, 6) << 14; - m_flag[1] |= _mm_extract_epi16(f8_mask, 7) << 15; -#endif - INT16 vres[8]; - UINT32 vce = 0; - for (int i = 0; i < 8; i++) - { - INT16 s1, s2; - VEC_GET_SCALAR_VS1(s1, i); - VEC_GET_SCALAR_VS2(s2, i); - - if ((s1 ^ s2) < 0) - { - vce = (s1 + s2 == -1); - VEC_SET_CARRY_FLAG(i); - if (s2 < 0) - { - VEC_SET_CLIP2_FLAG(i); - } - - if ((s1 + s2) <= 0) - { - VEC_SET_COMPARE_FLAG(i); - vres[i] = -((UINT16)s2); - } - else - { - vres[i] = s1; - } - - if ((s1 + s2) != 0 && s1 != ~s2) - { - VEC_SET_ZERO_FLAG(i); - } - }//sign - else - { - vce = 0; - if (s2 < 0) - { - VEC_SET_COMPARE_FLAG(i); - } - if ((s1 - s2) >= 0) - { - VEC_SET_CLIP2_FLAG(i); - vres[i] = s2; - } - else - { - vres[i] = s1; - } - - if ((s1 - s2) != 0 && s1 != ~s2) - { - VEC_SET_ZERO_FLAG(i); - } - } - if (vce) - { - VEC_SET_CLIP1_FLAG(i); - } - VEC_SET_ACCUM_L(vres[i], i); - } - VEC_WRITEBACK_RESULT(); -} - -static void cfunc_rsp_vch_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vch_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_vch_scalar() -{ - int op = m_rsp_state->arg0; - - CLEAR_CARRY_FLAGS(); - CLEAR_COMPARE_FLAGS(); - CLEAR_CLIP1_FLAGS(); - CLEAR_ZERO_FLAGS(); - CLEAR_CLIP2_FLAGS(); - - INT16 vres[8]; - UINT32 vce = 0; - for (int i = 0; i < 8; i++) - { - INT16 s1, s2; - SCALAR_GET_VS1(s1, i); - SCALAR_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); - vres[i] = -((UINT16)s2); - } - else - { - 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); - vres[i] = s2; - } - else - { - vres[i] = s1; - } - - if ((s1 - s2) != 0 && s1 != ~s2) - { - SET_ZERO_FLAG(i); - } - } - if (vce) - { - SET_CLIP1_FLAG(i); - } - SET_ACCUM_L(vres[i], i); - } - WRITEBACK_RESULT(); -} - -static void cfunc_rsp_vch_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vch_scalar(); -} -#endif - -#if USE_SIMD -// VCR -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100110 | -// ------------------------------------------------------ -// -// Vector clip reverse - -inline void rsp_device::ccfunc_rsp_vcr_simd() -{ - int op = m_rsp_state->arg0; - - VEC_CLEAR_CARRY_FLAGS(); - VEC_CLEAR_COMPARE_FLAGS(); - VEC_CLEAR_CLIP1_FLAGS(); - VEC_CLEAR_ZERO_FLAGS(); - VEC_CLEAR_CLIP2_FLAGS(); - -#if 0 - // flag[1] bit [0- 7] set if (s1 ^ s2) < 0 && (s1 + s2) <= 0) - // flag[1] bit [0- 7] set if (s1 ^ s2) >= 0 && (s2 < 0) - - // flag[1] bit [8-15] set if (s1 ^ s2) < 0 && (s2 < 0) - // flag[1] bit [8-15] set if (s1 ^ s2) >= 0 && (s1 - s2) >= 0 - - // accum set to ~s2 if (s1 ^ s2) < 0 && (s1 + s2) <= 0) - // accum set to ~s2 if (s1 ^ s2) >= 0 && (s1 - s2) >= 0 - - // accum set to s1 if (s1 ^ s2) < 0 && (s1 + s2) > 0) - // accum set to s1 if (s1 ^ s2) >= 0 && (s1 - s2) < 0 - __m128i shuf = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); - __m128i s1_xor_s2 = _mm_xor_si128(m_xv[VS1REG], shuf); - __m128i s1_plus_s2 = _mm_add_epi16(m_xv[VS1REG], shuf); - __m128i s1_sub_s2 = _mm_sub_epi16(m_xv[VS1REG], shuf); - __m128i s2_neg = _mm_xor_si128(shuf, vec_neg1); - - __m128i s2_lz = _mm_cmplt_epi16(shuf, _mm_setzero_si128()); - __m128i s1s2_xor_lz = _mm_cmplt_epi16(s1_xor_s2, _mm_setzero_si128()); - __m128i s1s2_xor_gez = _mm_xor_si128(s1s2_xor_lz, vec_neg1); - __m128i s1s2_plus_gz = _mm_cmpgt_epi16(s1_plus_s2, _mm_setzero_si128()); - __m128i s1s2_plus_lez = _mm_xor_si128(s1s2_plus_gz, vec_neg1); - __m128i s1s2_sub_lz = _mm_cmplt_epi16(s1_sub_s2, _mm_setzero_si128()); - __m128i s1s2_sub_gez = _mm_xor_si128(s1s2_sub_lz, vec_neg1); - - __m128i s1_mask = _mm_or_si128(_mm_and_si128(s1s2_xor_gez, s1s2_sub_lz), _mm_and_si128(s1s2_xor_lz, s1s2_plus_gz)); - __m128i s2_mask = _mm_or_si128(_mm_and_si128(s1s2_xor_gez, s1s2_sub_gez), _mm_and_si128(s1s2_xor_lz, s1s2_plus_lez)); - m_accum_l = _mm_or_si128(_mm_and_si128(m_xv[VS1REG], s1_mask), _mm_and_si128(s2_neg, s2_mask)); - m_xv[VDREG] = m_accum_l; - - m_xvflag[COMPARE] = _mm_or_si128(_mm_and_si128(s1s2_xor_gez, s2_lz), _mm_and_si128(s1s2_xor_lz, s1s2_plus_lez)); - m_xvflag[CLIP2] = _mm_or_si128(_mm_and_si128(s1s2_xor_gez, s1s2_sub_gez), _mm_and_si128(s1s2_xor_lz, s2_lz)); -#endif - INT16 vres[8]; - for (int i = 0; i < 8; i++) - { - INT16 s1, s2; - VEC_GET_SCALAR_VS1(s1, i); - VEC_GET_SCALAR_VS2(s2, i); - - if ((INT16)(s1 ^ s2) < 0) - { - if (s2 < 0) - { - VEC_SET_CLIP2_FLAG(i); - } - if ((s1 + s2) <= 0) - { - VEC_SET_ACCUM_L(~((UINT16)s2), i); - VEC_SET_COMPARE_FLAG(i); - } - else - { - VEC_SET_ACCUM_L(s1, i); - } - } - else - { - if (s2 < 0) - { - VEC_SET_COMPARE_FLAG(i); - } - if ((s1 - s2) >= 0) - { - VEC_SET_ACCUM_L(s2, i); - VEC_SET_CLIP2_FLAG(i); - } - else - { - VEC_SET_ACCUM_L(s1, i); - } - } - - vres[i] = VEC_ACCUM_L(i); - } - VEC_WRITEBACK_RESULT(); -} - -static void cfunc_rsp_vcr_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vcr_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_vcr_scalar() -{ - int op = m_rsp_state->arg0; - - CLEAR_CARRY_FLAGS(); - CLEAR_COMPARE_FLAGS(); - CLEAR_CLIP1_FLAGS(); - CLEAR_ZERO_FLAGS(); - CLEAR_CLIP2_FLAGS(); - - INT16 vres[8]; - for (int i = 0; i < 8; i++) - { - INT16 s1, s2; - SCALAR_GET_VS1(s1, i); - SCALAR_GET_VS2(s2, i); - - if ((INT16)(s1 ^ s2) < 0) - { - if (s2 < 0) - { - SET_CLIP2_FLAG(i); - } - if ((s1 + s2) <= 0) - { - SET_ACCUM_L(~((UINT16)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); - } - } - - vres[i] = ACCUM_L(i); - } - WRITEBACK_RESULT(); -} - -static void cfunc_rsp_vcr_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vcr_scalar(); -} -#endif - -#if USE_SIMD -// VMRG -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100111 | -// ------------------------------------------------------ -// -// Merges two vectors according to compare flags - -inline void rsp_device::ccfunc_rsp_vmrg_simd() -{ - int op = m_rsp_state->arg0; - - __m128i shuf = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); - __m128i s2mask = _mm_cmpeq_epi16(m_xvflag[COMPARE], _mm_setzero_si128()); - __m128i s1mask = _mm_xor_si128(s2mask, vec_neg1); - __m128i result = _mm_and_si128(m_xv[VS1REG], s1mask); - m_xv[VDREG] = _mm_or_si128(result, _mm_and_si128(shuf, s2mask)); - m_accum_l = m_xv[VDREG]; -} - -static void cfunc_rsp_vmrg_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vmrg_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_vmrg_scalar() -{ - int op = m_rsp_state->arg0; - - INT16 vres[8]; - for (int i = 0; i < 8; i++) - { - INT16 s1, s2; - SCALAR_GET_VS1(s1, i); - SCALAR_GET_VS2(s2, i); - if (COMPARE_FLAG(i) != 0) - { - vres[i] = s1; - } - else - { - vres[i] = s2; - } - - SET_ACCUM_L(vres[i], i); - } - WRITEBACK_RESULT(); -} - -static void cfunc_rsp_vmrg_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vmrg_scalar(); -} -#endif - -#if USE_SIMD -// VAND -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101000 | -// ------------------------------------------------------ -// -// Bitwise AND of two vector registers - -inline void rsp_device::ccfunc_rsp_vand_simd() -{ - int op = m_rsp_state->arg0; - - __m128i shuf = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); - m_xv[VDREG] = _mm_and_si128(m_xv[VS1REG], shuf); - m_accum_l = m_xv[VDREG]; -} - -static void cfunc_rsp_vand_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vand_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_vand_scalar() -{ - int op = m_rsp_state->arg0; - - INT16 vres[8]; - for (int i = 0; i < 8; i++) - { - UINT16 s1, s2; - SCALAR_GET_VS1(s1, i); - SCALAR_GET_VS2(s2, i); - vres[i] = s1 & s2; - SET_ACCUM_L(vres[i], i); - } - WRITEBACK_RESULT(); -} - -static void cfunc_rsp_vand_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vand_scalar(); -} -#endif - -#if USE_SIMD -// VNAND -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101001 | -// ------------------------------------------------------ -// -// Bitwise NOT AND of two vector registers - -inline void rsp_device::ccfunc_rsp_vnand_simd() -{ - int op = m_rsp_state->arg0; - - __m128i shuf = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); - m_xv[VDREG] = _mm_xor_si128(_mm_and_si128(m_xv[VS1REG], shuf), vec_neg1); - m_accum_l = m_xv[VDREG]; -} - -static void cfunc_rsp_vnand_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vnand_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_vnand_scalar() -{ - int op = m_rsp_state->arg0; - - INT16 vres[8]; - for (int i = 0; i < 8; i++) - { - UINT16 s1, s2; - SCALAR_GET_VS1(s1, i); - SCALAR_GET_VS2(s2, i); - vres[i] = ~((s1 & s2)); - SET_ACCUM_L(vres[i], i); - } - WRITEBACK_RESULT(); -} - -static void cfunc_rsp_vnand_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vnand_scalar(); -} -#endif - -#if USE_SIMD -// VOR -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101010 | -// ------------------------------------------------------ -// -// Bitwise OR of two vector registers - -inline void rsp_device::ccfunc_rsp_vor_simd() -{ - int op = m_rsp_state->arg0; - - __m128i shuf = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); - m_xv[VDREG] = _mm_or_si128(m_xv[VS1REG], shuf); - m_accum_l = m_xv[VDREG]; -} - -static void cfunc_rsp_vor_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vor_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_vor_scalar() -{ - int op = m_rsp_state->arg0; - - INT16 vres[8]; - for (int i = 0; i < 8; i++) - { - UINT16 s1, s2; - SCALAR_GET_VS1(s1, i); - SCALAR_GET_VS2(s2, i); - vres[i] = s1 | s2; - SET_ACCUM_L(vres[i], i); - } - WRITEBACK_RESULT(); -} - -static void cfunc_rsp_vor_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vor_scalar(); -} -#endif - -#if USE_SIMD -// VNOR -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101011 | -// ------------------------------------------------------ -// -// Bitwise NOT OR of two vector registers - -inline void rsp_device::ccfunc_rsp_vnor_simd() -{ - int op = m_rsp_state->arg0; - - __m128i shuf = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); - m_xv[VDREG] = _mm_xor_si128(_mm_or_si128(m_xv[VS1REG], shuf), vec_neg1); - m_accum_l = m_xv[VDREG]; -} - -static void cfunc_rsp_vnor_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vnor_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_vnor_scalar() -{ - int op = m_rsp_state->arg0; - - INT16 vres[8]; - for (int i = 0; i < 8; i++) - { - UINT16 s1, s2; - SCALAR_GET_VS1(s1, i); - SCALAR_GET_VS2(s2, i); - vres[i] = ~(s1 | s2); - SET_ACCUM_L(vres[i], i); - } - WRITEBACK_RESULT(); -} - -static void cfunc_rsp_vnor_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vnor_scalar(); -} -#endif - -#if USE_SIMD -// VXOR -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101100 | -// ------------------------------------------------------ -// -// Bitwise XOR of two vector registers - -inline void rsp_device::ccfunc_rsp_vxor_simd() -{ - int op = m_rsp_state->arg0; - - __m128i shuf = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); - m_xv[VDREG] = _mm_xor_si128(m_xv[VS1REG], shuf); - m_accum_l = m_xv[VDREG]; -} - -static void cfunc_rsp_vxor_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vxor_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_vxor_scalar() -{ - int op = m_rsp_state->arg0; - - INT16 vres[8]; - for (int i = 0; i < 8; i++) - { - UINT16 s1, s2; - SCALAR_GET_VS1(s1, i); - SCALAR_GET_VS2(s2, i); - vres[i] = s1 ^ s2; - SET_ACCUM_L(vres[i], i); - } - WRITEBACK_RESULT(); -} - -static void cfunc_rsp_vxor_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vxor_scalar(); -} -#endif - -#if USE_SIMD -// VNXOR -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101101 | -// ------------------------------------------------------ -// -// Bitwise NOT XOR of two vector registers - -inline void rsp_device::ccfunc_rsp_vnxor_simd() -{ - int op = m_rsp_state->arg0; - - __m128i shuf = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); - m_xv[VDREG] = _mm_xor_si128(_mm_xor_si128(m_xv[VS1REG], shuf), vec_neg1); - m_accum_l = m_xv[VDREG]; -} - -static void cfunc_rsp_vnxor_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vnxor_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_vnxor_scalar() -{ - int op = m_rsp_state->arg0; - - INT16 vres[8]; - for (int i = 0; i < 8; i++) - { - UINT16 s1, s2; - SCALAR_GET_VS1(s1, i); - SCALAR_GET_VS2(s2, i); - vres[i] = ~(s1 ^ s2); - SET_ACCUM_L(vres[i], i); - } - WRITEBACK_RESULT(); -} - -static void cfunc_rsp_vnxor_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vnxor_scalar(); -} -#endif - -#if USE_SIMD -// VRCP -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110000 | -// ------------------------------------------------------ -// -// Calculates reciprocal - -inline void rsp_device::ccfunc_rsp_vrcp_simd() -{ - int op = m_rsp_state->arg0; - - INT32 shifter = 0; - UINT16 urec; - INT32 rec; - SIMD_EXTRACT16(m_xv[VS2REG], urec, EL); - rec = (INT16)urec; - INT32 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 address = ((datainput << shifter) & 0x7fc00000) >> 22; - INT32 fetchval = rsp_divtable[address]; - INT32 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; - - SIMD_INSERT16(m_xv[VDREG], (UINT16)rec, VS1REG); - m_accum_l = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); -} - -static void cfunc_rsp_vrcp_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vrcp_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_vrcp_scalar() -{ - int op = m_rsp_state->arg0; - - INT32 shifter = 0; - INT32 rec = (INT16)(VREG_S(VS2REG, EL & 7)); - INT32 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 address = ((datainput << shifter) & 0x7fc00000) >> 22; - INT32 fetchval = rsp_divtable[address]; - INT32 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)rec; - for (int i = 0; i < 8; i++) - { - SET_ACCUM_L(VREG_S(VS2REG, VEC_EL_2(EL, i)), i); - } } -static void cfunc_rsp_vrcp_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vrcp_scalar(); -} -#endif - -#if USE_SIMD -// VRCPL -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110001 | -// ------------------------------------------------------ -// -// Calculates reciprocal low part - -inline void rsp_device::ccfunc_rsp_vrcpl_simd() -{ - int op = m_rsp_state->arg0; - -#if SIMUL_SIMD - m_old_reciprocal_res = m_reciprocal_res; - m_old_reciprocal_high = m_reciprocal_high; - m_old_dp_allowed = m_dp_allowed; -#endif - - INT32 shifter = 0; - - UINT16 urec; - SIMD_EXTRACT16(m_xv[VS2REG], urec, EL); - INT32 rec = (INT16)urec; - INT32 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 address = ((datainput << shifter) & 0x7fc00000) >> 22; - INT32 fetchval = rsp_divtable[address]; - INT32 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; - - SIMD_INSERT16(m_xv[VDREG], (UINT16)rec, VS1REG); - - for (int i = 0; i < 8; i++) - { - INT16 val; - SIMD_EXTRACT16(m_xv[VS2REG], val, VEC_EL_2(EL, i)); - VEC_SET_ACCUM_L(val, i); - } -} - -static void cfunc_rsp_vrcpl_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vrcpl_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_vrcpl_scalar() -{ - int op = m_rsp_state->arg0; - - INT32 shifter = 0; - INT32 rec = (INT16)VREG_S(VS2REG, EL & 7); - INT32 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 address = (datainput << shifter) >> 22; - INT32 fetchval = rsp_divtable[address & 0x1ff]; - INT32 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)rec; - - for (int i = 0; i < 8; i++) - { - SET_ACCUM_L(VREG_S(VS2REG, VEC_EL_2(EL, i)), i); - } -} - -static void cfunc_rsp_vrcpl_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vrcpl_scalar(); -} -#endif - -#if USE_SIMD -// VRCPH -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110010 | -// ------------------------------------------------------ -// -// Calculates reciprocal high part - -inline void rsp_device::ccfunc_rsp_vrcph_simd() -{ - int op = m_rsp_state->arg0; - -#if SIMUL_SIMD - m_old_reciprocal_res = m_reciprocal_res; - m_old_reciprocal_high = m_reciprocal_high; - m_old_dp_allowed = m_dp_allowed; -#endif - - UINT16 rcph; - SIMD_EXTRACT16(m_xv[VS2REG], rcph, EL); - m_reciprocal_high = rcph << 16; - m_dp_allowed = 1; - - m_accum_l = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); - - SIMD_INSERT16(m_xv[VDREG], (INT16)(m_reciprocal_res >> 16), VS1REG); -} - -static void cfunc_rsp_vrcph_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vrcph_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_vrcph_scalar() -{ - int op = m_rsp_state->arg0; - - 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)(m_reciprocal_res >> 16); -} - -static void cfunc_rsp_vrcph_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vrcph_scalar(); -} -#endif - -#if USE_SIMD -// VMOV -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110011 | -// ------------------------------------------------------ -// -// Moves element from vector to destination vector - -inline void rsp_device::ccfunc_rsp_vmov_simd() -{ - int op = m_rsp_state->arg0; - - INT16 val; - SIMD_EXTRACT16(m_xv[VS2REG], val, EL); - SIMD_INSERT16(m_xv[VDREG], val, VS1REG); - m_accum_l = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); -} - -static void cfunc_rsp_vmov_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vmov_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_vmov_scalar() -{ - int op = m_rsp_state->arg0; - - 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); - } -} - -static void cfunc_rsp_vmov_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vmov_scalar(); -} -#endif - -// VRSQ -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110100 | -// ------------------------------------------------------ -// -// Calculates reciprocal square-root - -inline void rsp_device::ccfunc_rsp_vrsq_scalar() -{ - int op = m_rsp_state->arg0; - - INT32 shifter = 0; - INT32 rec = (INT16)VREG_S(VS2REG, EL & 7); - INT32 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 address = ((datainput << shifter) & 0x7fc00000) >> 22; - address = ((address | 0x200) & 0x3fe) | (shifter & 1); - - INT32 fetchval = rsp_divtable[address]; - INT32 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)rec; - for (int i = 0; i < 8; i++) - { - SET_ACCUM_L(VREG_S(VS2REG, VEC_EL_2(EL, i)), i); - } -} - -static void cfunc_rsp_vrsq_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vrsq_scalar(); -} - -#if USE_SIMD -// VRSQL -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110101 | -// ------------------------------------------------------ -// -// Calculates reciprocal square-root low part - -inline void rsp_device::ccfunc_rsp_vrsql_simd() -{ - int op = m_rsp_state->arg0; - -#if SIMUL_SIMD - m_old_reciprocal_res = m_reciprocal_res; - m_old_reciprocal_high = m_reciprocal_high; - m_old_dp_allowed = m_dp_allowed; -#endif - - INT32 shifter = 0; - UINT16 val; - SIMD_EXTRACT16(m_xv[VS2REG], val, EL); - INT32 rec = (INT16)val; - INT32 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 address = ((datainput << shifter) & 0x7fc00000) >> 22; - address = ((address | 0x200) & 0x3fe) | (shifter & 1); - - INT32 fetchval = rsp_divtable[address]; - INT32 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; - - SIMD_INSERT16(m_xv[VDREG], (UINT16)rec, VS1REG); - m_accum_l = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); -} - -static void cfunc_rsp_vrsql_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vrsql_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_vrsql_scalar() -{ - int op = m_rsp_state->arg0; - - INT32 shifter = 0; - INT32 rec = (INT16)VREG_S(VS2REG, EL & 7); - INT32 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 address = ((datainput << shifter) & 0x7fc00000) >> 22; - address = ((address | 0x200) & 0x3fe) | (shifter & 1); - - INT32 fetchval = rsp_divtable[address]; - INT32 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)(rec & 0xffff); - for (int i = 0; i < 8; i++) - { - SET_ACCUM_L(VREG_S(VS2REG, VEC_EL_2(EL, i)), i); - } -} - -static void cfunc_rsp_vrsql_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vrsql_scalar(); -} -#endif - -#if USE_SIMD -// VRSQH -// -// 31 25 24 20 15 10 5 0 -// ------------------------------------------------------ -// | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110110 | -// ------------------------------------------------------ -// -// Calculates reciprocal square-root high part - -inline void rsp_device::ccfunc_rsp_vrsqh_simd() -{ - int op = m_rsp_state->arg0; - -#if SIMUL_SIMD - m_old_reciprocal_res = m_reciprocal_res; - m_old_reciprocal_high = m_reciprocal_high; - m_old_dp_allowed = m_dp_allowed; -#endif - - UINT16 val; - SIMD_EXTRACT16(m_xv[VS2REG], val, EL); - m_reciprocal_high = val << 16; - m_dp_allowed = 1; - - m_accum_l = _mm_shuffle_epi8(m_xv[VS2REG], vec_shuf_inverse[EL]); - - SIMD_INSERT16(m_xv[VDREG], (INT16)(m_reciprocal_res >> 16), VS1REG); // store high part -} - -static void cfunc_rsp_vrsqh_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vrsqh_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) - -inline void rsp_device::ccfunc_rsp_vrsqh_scalar() -{ - int op = m_rsp_state->arg0; - - 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)(m_reciprocal_res >> 16); // store high part -} - -static void cfunc_rsp_vrsqh_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_rsp_vrsqh_scalar(); -} -#endif - - inline void rsp_device::ccfunc_sp_set_status_cb() { m_sp_set_status_func(0, m_rsp_state->arg0, 0xffffffff); @@ -7355,7 +677,7 @@ void rsp_device::static_generate_memory_accessor(int size, int iswrite, const ch if (size == 1) { UML_MOV(block, mem(&m_rsp_state->arg0), I0); // mov [arg0],i0 ; address - UML_CALLC(block, cfunc_read8, this); // callc cfunc_printf_debug + 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) @@ -7581,719 +903,6 @@ void rsp_device::generate_delay_slot_and_branch(drcuml_block *block, compiler_st UML_MAPVAR(block, MAPVAR_CYCLES, compiler->cycles); // mapvar CYCLES,compiler->cycles } - -/*------------------------------------------------- - generate_vector_opcode - generate code for a - vector opcode --------------------------------------------------*/ - -#if USE_SIMD - -int rsp_device::generate_vector_opcode(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) -{ - UINT32 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_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vmulf_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_vmulf_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - - case 0x01: /* VMULU */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vmulu_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_vmulu_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - - case 0x04: /* VMUDL */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vmudl_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_vmudl_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - - case 0x05: /* VMUDM */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vmudm_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_vmudm_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - - case 0x06: /* VMUDN */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vmudn_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_vmudn_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - - case 0x07: /* VMUDH */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vmudh_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_vmudh_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - - case 0x08: /* VMACF */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vmacf_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_vmacf_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - - case 0x09: /* VMACU */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vmacu_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_vmacu_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - - case 0x0c: /* VMADL */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vmadl_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_vmadl_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - - case 0x0d: /* VMADM */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vmadm_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_vmadm_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - - case 0x0e: /* VMADN */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vmadn_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_vmadn_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - - case 0x0f: /* VMADH */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vmadh_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_vmadh_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - - case 0x10: /* VADD */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vadd_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_vadd_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - - case 0x11: /* VSUB */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vsub_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_vsub_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - - case 0x13: /* VABS */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vabs_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_vabs_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - - case 0x14: /* VADDC */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vaddc_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_vaddc_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - - case 0x15: /* VSUBC */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vsubc_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_vsubc_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - - case 0x16: /* VADDB */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vaddb_scalar, this); - return TRUE; - - case 0x17: /* VSUBB (reserved, functionally identical to VADDB) */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vaddb_scalar, this); - return TRUE; - - case 0x18: /* VACCB (reserved, functionally identical to VADDB) */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vaddb_scalar, this); - return TRUE; - - case 0x19: /* VSUCB (reserved, functionally identical to VADDB) */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vaddb_scalar, this); - return TRUE; - - case 0x1d: /* VSAW */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vsaw_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_vsaw_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - - case 0x20: /* VLT */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vlt_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_vlt_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - - case 0x21: /* VEQ */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_veq_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_veq_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - - case 0x22: /* VNE */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vne_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_vne_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - - case 0x23: /* VGE */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vge_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_vge_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - - case 0x24: /* VCL */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vcl_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_vcl_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - - case 0x25: /* VCH */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vch_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_vch_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - - case 0x26: /* VCR */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vcr_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_vcr_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - - case 0x27: /* VMRG */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vmrg_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_vmrg_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - - case 0x28: /* VAND */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vand_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_vand_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - - case 0x29: /* VNAND */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vnand_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_vnand_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - - case 0x2a: /* VOR */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vor_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_vor_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - - case 0x2b: /* VNOR */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vnor_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_vnor_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - - case 0x2c: /* VXOR */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vxor_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_vxor_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - - case 0x2d: /* VNXOR */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vnxor_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_vnxor_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - - case 0x30: /* VRCP */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vrcp_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_vrcp_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - - case 0x31: /* VRCPL */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vrcpl_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_vrcpl_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - - case 0x32: /* VRCPH */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vrcph_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_vrcph_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - - case 0x33: /* VMOV */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vmov_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_vmov_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - - case 0x34: /* VRSQ */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC_block, cfunc_rsp_vrsq_scalar, this); - return TRUE; - - case 0x35: /* VRSQL */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vrsql_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_vrsql_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - - case 0x36: /* VRSQH */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vrsqh_simd, this); -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_rsp_vrsqh_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif - return TRUE; - - case 0x37: /* VNOP */ - case 0x3F: /* VNULL */ - return TRUE; - - default: - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_unimplemented_opcode, this); - return FALSE; - } -} - -#else - -int rsp_device::generate_vector_opcode(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) -{ - UINT32 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_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vmulf_scalar, this); - return TRUE; - - case 0x01: /* VMULU */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vmulu_scalar, this); - return TRUE; - - case 0x04: /* VMUDL */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vmudl_scalar, this); - return TRUE; - - case 0x05: /* VMUDM */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vmudm_scalar, this); - return TRUE; - - case 0x06: /* VMUDN */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vmudn_scalar, this); - return TRUE; - - case 0x07: /* VMUDH */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vmudh_scalar, this); - return TRUE; - - case 0x08: /* VMACF */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vmacf_scalar, this); - return TRUE; - - case 0x09: /* VMACU */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vmacu_scalar, this); - return TRUE; - - case 0x0c: /* VMADL */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vmadl_scalar, this); - return TRUE; - - case 0x0d: /* VMADM */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vmadm_scalar, this); - return TRUE; - - case 0x0e: /* VMADN */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vmadn_scalar, this); - return TRUE; - - case 0x0f: /* VMADH */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vmadh_scalar, this); - return TRUE; - - case 0x10: /* VADD */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vadd_scalar, this); - return TRUE; - - case 0x11: /* VSUB */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vsub_scalar, this); - return TRUE; - - case 0x13: /* VABS */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vabs_scalar, this); - return TRUE; - - case 0x14: /* VADDC */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vaddc_scalar, this); - return TRUE; - - case 0x15: /* VSUBC */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vsubc_scalar, this); - return TRUE; - - case 0x16: /* VADDB */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vaddb_scalar, this); - return TRUE; - - case 0x17: /* VSUBB (reserved, functionally identical to VADDB) */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vaddb_scalar, this); - return TRUE; - - case 0x18: /* VACCB (reserved, functionally identical to VADDB) */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vaddb_scalar, this); - return TRUE; - - case 0x19: /* VSUCB (reserved, functionally identical to VADDB) */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vaddb_scalar, this); - return TRUE; - - case 0x1d: /* VSAW */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vsaw_scalar, this); - return TRUE; - - case 0x20: /* VLT */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vlt_scalar, this); - return TRUE; - - case 0x21: /* VEQ */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_veq_scalar, this); - return TRUE; - - case 0x22: /* VNE */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vne_scalar, this); - return TRUE; - - case 0x23: /* VGE */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vge_scalar, this); - return TRUE; - - case 0x24: /* VCL */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vcl_scalar, this); - return TRUE; - - case 0x25: /* VCH */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vch_scalar, this); - return TRUE; - - case 0x26: /* VCR */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vcr_scalar, this); - return TRUE; - - case 0x27: /* VMRG */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vmrg_scalar, this); - return TRUE; - - case 0x28: /* VAND */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vand_scalar, this); - return TRUE; - - case 0x29: /* VNAND */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vnand_scalar, this); - return TRUE; - - case 0x2a: /* VOR */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vor_scalar, this); - return TRUE; - - case 0x2b: /* VNOR */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vnor_scalar, this); - return TRUE; - - case 0x2c: /* VXOR */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vxor_scalar, this); - return TRUE; - - case 0x2d: /* VNXOR */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vnxor_scalar, this); - return TRUE; - - case 0x30: /* VRCP */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vrcp_scalar, this); - return TRUE; - - case 0x31: /* VRCPL */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vrcpl_scalar, this); - return TRUE; - - case 0x32: /* VRCPH */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vrcph_scalar, this); - return TRUE; - - case 0x33: /* VMOV */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vmov_scalar, this); - return TRUE; - - case 0x34: /* VRSQ */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vrsq_scalar, this); - return TRUE; - - case 0x35: /* VRSQL */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vrsql_scalar, this); - return TRUE; - - case 0x36: /* VRSQH */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_rsp_vrsqh_scalar, this); - return TRUE; - - case 0x37: /* VNOP */ - case 0x3F: /* VNULL */ - return TRUE; - - default: - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - UML_CALLC(block, cfunc_unimplemented_opcode, this); - return FALSE; - } -} -#endif - int 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); @@ -8450,7 +1059,7 @@ int rsp_device::generate_opcode(drcuml_block *block, compiler_state *compiler, c return TRUE; case 0x32: /* LWC2 - MIPS I */ - return generate_lwc2(block, compiler, desc); + return m_cop2->generate_lwc2(block, compiler, desc); /* ----- memory store operations ----- */ @@ -8480,10 +1089,7 @@ int rsp_device::generate_opcode(drcuml_block *block, compiler_state *compiler, c return TRUE; case 0x3a: /* SWC2 - MIPS I */ - return generate_swc2(block, compiler, desc); - //UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l - //UML_CALLC(block, cfunc_swc2, this); // callc cfunc_mfc2 - //return TRUE; + return m_cop2->generate_swc2(block, compiler, desc); /* ----- coprocessor instructions ----- */ @@ -8491,9 +1097,7 @@ int rsp_device::generate_opcode(drcuml_block *block, compiler_state *compiler, c return generate_cop0(block, compiler, desc); case 0x12: /* COP2 - MIPS I */ - return generate_cop2(block, compiler, desc); - //UML_EXH(block, m_exception[EXCEPTION_INVALIDOP], 0);// exh invalidop,0 - //return TRUE; + return m_cop2->generate_cop2(block, compiler, desc); /* ----- unimplemented/illegal instructions ----- */ @@ -8705,92 +1309,6 @@ int rsp_device::generate_regimm(drcuml_block *block, compiler_state *compiler, c /*------------------------------------------------- - generate_cop2 - compile COP2 opcodes --------------------------------------------------*/ - -int rsp_device::generate_cop2(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) -{ - UINT32 op = desc->opptr.l[0]; - UINT8 opswitch = RSREG; - - switch (opswitch) - { - case 0x00: /* MFCz */ - if (RTREG != 0) - { - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l -#if USE_SIMD - UML_CALLC(block, cfunc_mfc2_simd, this); // callc cfunc_ctc2 -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_mfc2_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif -#else - UML_CALLC(block, cfunc_mfc2_scalar, this); -#endif - //UML_SEXT(block, R32(RTREG), I0, DWORD); // dsext <rtreg>,i0,dword - } - return TRUE; - - case 0x02: /* CFCz */ - if (RTREG != 0) - { - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l -#if USE_SIMD - UML_CALLC(block, cfunc_cfc2_simd, this); // callc cfunc_ctc2 -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_cfc2_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif -#else - UML_CALLC(block, cfunc_cfc2_scalar, this); -#endif - //UML_SEXT(block, R32(RTREG), I0, DWORD); // dsext <rtreg>,i0,dword - } - return TRUE; - - case 0x04: /* MTCz */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l -#if USE_SIMD - UML_CALLC(block, cfunc_mtc2_simd, this); // callc cfunc_ctc2 -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_mtc2_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif -#else - UML_CALLC(block, cfunc_mtc2_scalar, this); -#endif - return TRUE; - - case 0x06: /* CTCz */ - UML_MOV(block, mem(&m_rsp_state->arg0), desc->opptr.l[0]); // mov [arg0],desc->opptr.l -#if USE_SIMD - UML_CALLC(block, cfunc_ctc2_simd, this); // callc cfunc_ctc2 -#if SIMUL_SIMD - UML_CALLC(block, cfunc_backup_regs, this); - UML_CALLC(block, cfunc_ctc2_scalar, this); - UML_CALLC(block, cfunc_restore_regs, this); - UML_CALLC(block, cfunc_verify_regs, this); -#endif -#else - UML_CALLC(block, cfunc_ctc2_scalar, this); -#endif - 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; -} - -/*------------------------------------------------- generate_cop0 - compile COP0 opcodes -------------------------------------------------*/ @@ -8825,423 +1343,6 @@ int rsp_device::generate_cop0(drcuml_block *block, compiler_state *compiler, con return FALSE; } -#if USE_SIMD -inline void rsp_device::ccfunc_mfc2_simd() -{ - UINT32 op = m_rsp_state->arg0; - int el = (op >> 7) & 0xf; - - UINT16 out; - SIMD_EXTRACT16(m_xv[VS1REG], out, (el >> 1)); - out >>= (1 - (el & 1)) * 8; - out &= 0x00ff; - - el++; - - UINT16 temp; - SIMD_EXTRACT16(m_xv[VS1REG], temp, (el >> 1)); - temp >>= (1 - (el & 1)) * 8; - temp &= 0x00ff; - - m_rsp_state->r[RTREG] = (INT32)(INT16)((out << 8) | temp); -} - -static void cfunc_mfc2_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_mfc2_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) -inline void rsp_device::ccfunc_mfc2_scalar() -{ - UINT32 op = m_rsp_state->arg0; - int el = (op >> 7) & 0xf; - - UINT16 b1 = VREG_B(VS1REG, (el+0) & 0xf); - UINT16 b2 = VREG_B(VS1REG, (el+1) & 0xf); - if (RTREG) RTVAL = (INT32)(INT16)((b1 << 8) | (b2)); -} - -static void cfunc_mfc2_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_mfc2_scalar(); -} -#endif - -#if USE_SIMD -inline void rsp_device::ccfunc_cfc2_simd() -{ - UINT32 op = m_rsp_state->arg0; - if (RTREG) - { - switch(RDREG) - { - case 0: - RTVAL = ((VEC_CARRY_FLAG(0) & 1) << 0) | - ((VEC_CARRY_FLAG(1) & 1) << 1) | - ((VEC_CARRY_FLAG(2) & 1) << 2) | - ((VEC_CARRY_FLAG(3) & 1) << 3) | - ((VEC_CARRY_FLAG(4) & 1) << 4) | - ((VEC_CARRY_FLAG(5) & 1) << 5) | - ((VEC_CARRY_FLAG(6) & 1) << 6) | - ((VEC_CARRY_FLAG(7) & 1) << 7) | - ((VEC_ZERO_FLAG(0) & 1) << 8) | - ((VEC_ZERO_FLAG(1) & 1) << 9) | - ((VEC_ZERO_FLAG(2) & 1) << 10) | - ((VEC_ZERO_FLAG(3) & 1) << 11) | - ((VEC_ZERO_FLAG(4) & 1) << 12) | - ((VEC_ZERO_FLAG(5) & 1) << 13) | - ((VEC_ZERO_FLAG(6) & 1) << 14) | - ((VEC_ZERO_FLAG(7) & 1) << 15); - if (RTVAL & 0x8000) RTVAL |= 0xffff0000; - break; - case 1: - RTVAL = ((VEC_COMPARE_FLAG(0) & 1) << 0) | - ((VEC_COMPARE_FLAG(1) & 1) << 1) | - ((VEC_COMPARE_FLAG(2) & 1) << 2) | - ((VEC_COMPARE_FLAG(3) & 1) << 3) | - ((VEC_COMPARE_FLAG(4) & 1) << 4) | - ((VEC_COMPARE_FLAG(5) & 1) << 5) | - ((VEC_COMPARE_FLAG(6) & 1) << 6) | - ((VEC_COMPARE_FLAG(7) & 1) << 7) | - ((VEC_CLIP2_FLAG(0) & 1) << 8) | - ((VEC_CLIP2_FLAG(1) & 1) << 9) | - ((VEC_CLIP2_FLAG(2) & 1) << 10) | - ((VEC_CLIP2_FLAG(3) & 1) << 11) | - ((VEC_CLIP2_FLAG(4) & 1) << 12) | - ((VEC_CLIP2_FLAG(5) & 1) << 13) | - ((VEC_CLIP2_FLAG(6) & 1) << 14) | - ((VEC_CLIP2_FLAG(7) & 1) << 15); - if (RTVAL & 0x8000) RTVAL |= 0xffff0000; - break; - case 2: - RTVAL = ((VEC_CLIP1_FLAG(0) & 1) << 0) | - ((VEC_CLIP1_FLAG(1) & 1) << 1) | - ((VEC_CLIP1_FLAG(2) & 1) << 2) | - ((VEC_CLIP1_FLAG(3) & 1) << 3) | - ((VEC_CLIP1_FLAG(4) & 1) << 4) | - ((VEC_CLIP1_FLAG(5) & 1) << 5) | - ((VEC_CLIP1_FLAG(6) & 1) << 6) | - ((VEC_CLIP1_FLAG(7) & 1) << 7); - break; - } - } -} - -static void cfunc_cfc2_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_cfc2_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) -inline void rsp_device::ccfunc_cfc2_scalar() -{ - UINT32 op = m_rsp_state->arg0; - 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; - } - } -} - -static void cfunc_cfc2_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_cfc2_scalar(); -} -#endif - -#if USE_SIMD -inline void rsp_device::ccfunc_mtc2_simd() -{ - UINT32 op = m_rsp_state->arg0; - int el = (op >> 7) & 0xf; - SIMD_INSERT16(m_xv[VS1REG], RTVAL, el >> 1); -} - -static void cfunc_mtc2_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_mtc2_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) -inline void rsp_device::ccfunc_mtc2_scalar() -{ - UINT32 op = m_rsp_state->arg0; - int el = (op >> 7) & 0xf; - VREG_B(VS1REG, (el+0) & 0xf) = (RTVAL >> 8) & 0xff; - VREG_B(VS1REG, (el+1) & 0xf) = (RTVAL >> 0) & 0xff; -} - -static void cfunc_mtc2_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_mtc2_scalar(); -} -#endif - -#if USE_SIMD -inline void rsp_device::ccfunc_ctc2_simd() -{ - UINT32 op = m_rsp_state->arg0; - switch(RDREG) - { - case 0: - VEC_CLEAR_CARRY_FLAGS(); - VEC_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)) { VEC_SET_CARRY_FLAG(0); } - if (RTVAL & (1 << 1)) { VEC_SET_CARRY_FLAG(1); } - if (RTVAL & (1 << 2)) { VEC_SET_CARRY_FLAG(2); } - if (RTVAL & (1 << 3)) { VEC_SET_CARRY_FLAG(3); } - if (RTVAL & (1 << 4)) { VEC_SET_CARRY_FLAG(4); } - if (RTVAL & (1 << 5)) { VEC_SET_CARRY_FLAG(5); } - if (RTVAL & (1 << 6)) { VEC_SET_CARRY_FLAG(6); } - if (RTVAL & (1 << 7)) { VEC_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)) { VEC_SET_ZERO_FLAG(0); } - if (RTVAL & (1 << 9)) { VEC_SET_ZERO_FLAG(1); } - if (RTVAL & (1 << 10)) { VEC_SET_ZERO_FLAG(2); } - if (RTVAL & (1 << 11)) { VEC_SET_ZERO_FLAG(3); } - if (RTVAL & (1 << 12)) { VEC_SET_ZERO_FLAG(4); } - if (RTVAL & (1 << 13)) { VEC_SET_ZERO_FLAG(5); } - if (RTVAL & (1 << 14)) { VEC_SET_ZERO_FLAG(6); } - if (RTVAL & (1 << 15)) { VEC_SET_ZERO_FLAG(7); } - break; - case 1: - VEC_CLEAR_COMPARE_FLAGS(); - VEC_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)) { VEC_SET_COMPARE_FLAG(0); } - if (RTVAL & (1 << 1)) { VEC_SET_COMPARE_FLAG(1); } - if (RTVAL & (1 << 2)) { VEC_SET_COMPARE_FLAG(2); } - if (RTVAL & (1 << 3)) { VEC_SET_COMPARE_FLAG(3); } - if (RTVAL & (1 << 4)) { VEC_SET_COMPARE_FLAG(4); } - if (RTVAL & (1 << 5)) { VEC_SET_COMPARE_FLAG(5); } - if (RTVAL & (1 << 6)) { VEC_SET_COMPARE_FLAG(6); } - if (RTVAL & (1 << 7)) { VEC_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)) { VEC_SET_CLIP2_FLAG(0); } - if (RTVAL & (1 << 9)) { VEC_SET_CLIP2_FLAG(1); } - if (RTVAL & (1 << 10)) { VEC_SET_CLIP2_FLAG(2); } - if (RTVAL & (1 << 11)) { VEC_SET_CLIP2_FLAG(3); } - if (RTVAL & (1 << 12)) { VEC_SET_CLIP2_FLAG(4); } - if (RTVAL & (1 << 13)) { VEC_SET_CLIP2_FLAG(5); } - if (RTVAL & (1 << 14)) { VEC_SET_CLIP2_FLAG(6); } - if (RTVAL & (1 << 15)) { VEC_SET_CLIP2_FLAG(7); } - break; - case 2: - VEC_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)) { VEC_SET_CLIP1_FLAG(0); } - if (RTVAL & (1 << 1)) { VEC_SET_CLIP1_FLAG(1); } - if (RTVAL & (1 << 2)) { VEC_SET_CLIP1_FLAG(2); } - if (RTVAL & (1 << 3)) { VEC_SET_CLIP1_FLAG(3); } - if (RTVAL & (1 << 4)) { VEC_SET_CLIP1_FLAG(4); } - if (RTVAL & (1 << 5)) { VEC_SET_CLIP1_FLAG(5); } - if (RTVAL & (1 << 6)) { VEC_SET_CLIP1_FLAG(6); } - if (RTVAL & (1 << 7)) { VEC_SET_CLIP1_FLAG(7); } - break; - } -} - -static void cfunc_ctc2_simd(void *param) -{ - ((rsp_device *)param)->ccfunc_ctc2_simd(); -} -#endif - -#if (!USE_SIMD || SIMUL_SIMD) -inline void rsp_device::ccfunc_ctc2_scalar() -{ - UINT32 op = m_rsp_state->arg0; - 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; - } -} - -static void cfunc_ctc2_scalar(void *param) -{ - ((rsp_device *)param)->ccfunc_ctc2_scalar(); -} -#endif - /*************************************************************************** CODE LOGGING HELPERS ***************************************************************************/ diff --git a/src/mame/drivers/sauro.c b/src/mame/drivers/sauro.c index 7e304f04e47..389a9f2f90b 100644 --- a/src/mame/drivers/sauro.c +++ b/src/mame/drivers/sauro.c @@ -491,6 +491,39 @@ ROM_START( saurop ) ROM_LOAD( "sp0256-al2.bin", 0x1000, 0x0800, CRC(b504ac15) SHA1(e60fcb5fa16ff3f3b69d36c7a6e955744d3feafc) ) ROM_END +ROM_START( saurorr ) // all roms have original Tecfri stickers + ROM_REGION( 0x10000, "maincpu", 0 ) + ROM_LOAD( "27256-2.bin", 0x00000, 0x8000, CRC(b0d80eab) SHA1(60cbe16d6c87d4681155814a5034b7e9d10bbd81) ) + ROM_LOAD( "27256-1.bin", 0x08000, 0x8000, CRC(cbb5f06e) SHA1(f93c01006d308e0b6950d720b6fe4409728c79e2) ) + + ROM_REGION( 0x10000, "audiocpu", 0 ) + ROM_LOAD( "sauro-3.bin", 0x00000, 0x8000, CRC(0d501e1b) SHA1(20a56ff30d4fa5d2f483a449703b49153839f6bc) ) + + ROM_REGION( 0x10000, "gfx1", 0 ) + ROM_LOAD( "sauro-6.bin", 0x00000, 0x8000, CRC(4b77cb0f) SHA1(7b9cb2dca561d81390106c1a5c0533dcecaf6f1a) ) + ROM_LOAD( "sauro-7.bin", 0x08000, 0x8000, CRC(187da060) SHA1(1df156e58379bb39acade02aabab6ff1cb7cc288) ) + + ROM_REGION( 0x10000, "gfx2", 0 ) + ROM_LOAD( "sauro-4.bin", 0x00000, 0x8000, CRC(9b617cda) SHA1(ce26b84ad5ecd6185ae218520e9972645bbf09ad) ) + ROM_LOAD( "27256-5.bin", 0x08000, 0x8000, CRC(9aabdbe5) SHA1(ef008e368024f9377a8d2bc5863b01c63bc8f55b) ) // contains the changed license logo + + ROM_REGION( 0x20000, "gfx3", 0 ) + ROM_LOAD( "sauro-8.bin", 0x00000, 0x8000, CRC(e08b5d5e) SHA1(eaaeaa08b19c034ab2a2140f887edffca5f441b9) ) + ROM_LOAD( "sauro-9.bin", 0x08000, 0x8000, CRC(7c707195) SHA1(0529f6808b0cec3e12ca51bee189841d21577786) ) + ROM_LOAD( "sauro-10.bin", 0x10000, 0x8000, CRC(c93380d1) SHA1(fc9655cc94c2d2058f83eb341be7e7856a08194f) ) + ROM_LOAD( "sauro-11.bin", 0x18000, 0x8000, CRC(f47982a8) SHA1(cbaeac272c015d9439f151cfb3449082f11a57a1) ) + + ROM_REGION( 0x0c00, "proms", 0 ) + ROM_LOAD( "82s137-3.bin", 0x0000, 0x0400, CRC(d52c4cd0) SHA1(27d6126b46616c06b55d8018c97f6c3d7805ae9e) ) /* Red component */ + ROM_LOAD( "82s137-2.bin", 0x0400, 0x0400, CRC(c3e96d5d) SHA1(3f6f21526a4357e4a9a9d56a6f4ef5911af2d120) ) /* Green component */ + ROM_LOAD( "82s137-1.bin", 0x0800, 0x0400, CRC(bdfcf00c) SHA1(9faf4d7f8959b64faa535c9945eec59c774a3760) ) /* Blue component */ + + ROM_REGION( 0x10000, "speech", 0 ) + /* SP0256 mask rom */ + ROM_LOAD( "sp0256-al2.bin", 0x1000, 0x0800, CRC(b504ac15) SHA1(e60fcb5fa16ff3f3b69d36c7a6e955744d3feafc) ) +ROM_END + + ROM_START( trckydoc ) ROM_REGION( 0x10000, "maincpu", 0 ) ROM_LOAD( "trckydoc.d9", 0x0000, 0x8000, CRC(c6242fc3) SHA1(c8a6f6abe8b51061a113ed75fead0479df68ec40) ) @@ -550,7 +583,9 @@ DRIVER_INIT_MEMBER(sauro_state,tecfri) RAM[0xe000] = 1; } -GAME( 1987, sauro, 0, sauro, tecfri, sauro_state, tecfri, ROT0, "Tecfri", "Sauro", 0 ) -GAME( 1987, saurop, sauro, sauro, tecfri, sauro_state, tecfri, ROT0, "Tecfri (Philko license)", "Sauro (Philko license)", 0 ) +GAME( 1987, sauro, 0, sauro, tecfri, sauro_state, tecfri, ROT0, "Tecfri", "Sauro", 0 ) +GAME( 1987, saurop, sauro, sauro, tecfri, sauro_state, tecfri, ROT0, "Tecfri (Philko license)", "Sauro (Philko license)", 0 ) +GAME( 1987, saurorr, sauro, sauro, tecfri, sauro_state, tecfri, ROT0, "Tecfri (Recreativo Real S.A. license)", "Sauro (Recreativo Real S.A. license)", 0 ) + GAME( 1987, trckydoc, 0, trckydoc, tecfri, sauro_state, tecfri, ROT0, "Tecfri", "Tricky Doc (set 1)", 0 ) GAME( 1987, trckydoca,trckydoc, trckydoc, trckydoca, sauro_state, tecfri, ROT0, "Tecfri", "Tricky Doc (set 2)", 0 ) diff --git a/src/mame/mame.lst b/src/mame/mame.lst index 9e9cafacb8f..ac73ac51ef2 100644 --- a/src/mame/mame.lst +++ b/src/mame/mame.lst @@ -9310,6 +9310,7 @@ speedbal // (c) 1987 musicbal // (c) 1987 sauro // (c) 1987 saurop // (c) 1987 +saurorr // (c) 1987 trckydoc // (c) 1987 trckydoca // (c) 1987 |