diff options
Diffstat (limited to 'src/emu/cpu/rsp/rspcp2.c')
-rw-r--r-- | src/emu/cpu/rsp/rspcp2.c | 1536 |
1 files changed, 1500 insertions, 36 deletions
diff --git a/src/emu/cpu/rsp/rspcp2.c b/src/emu/cpu/rsp/rspcp2.c index 8371583c948..cde6f3b5be8 100644 --- a/src/emu/cpu/rsp/rspcp2.c +++ b/src/emu/cpu/rsp/rspcp2.c @@ -1,23 +1,591 @@ // license:BSD-3-Clause -// copyright-holders:Ryan Holtz +// copyright-holders:Ryan Holtz,Tyler J. Stachecki /*************************************************************************** rspcp2.c Universal machine language-based Nintendo/SGI RSP COP2 emulator. - Written by Harmony of the MESS team. + Written by Ryan Holtz of the MAME team. ***************************************************************************/ #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; +#if USE_SIMD +#include <emmintrin.h> + +const rsp_cop2::vec_helpers_t rsp_cop2::m_vec_helpers = { + { 0 }, + { // logic_mask + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff } + }, + { // vrsq_mask_table + { 0xffff, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0xffff, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0xffff, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0xffff, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0xffff, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0xffff, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0xffff, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0xffff } + }, + { // shuffle_keys + { 0x0100, 0x0302, 0x0504, 0x0706, 0x0908, 0x0b0a, 0x0d0c, 0x0f0e }, /* -- */ + { 0x0100, 0x0302, 0x0504, 0x0706, 0x0908, 0x0b0a, 0x0d0c, 0x0f0e }, /* -- */ + + { 0x0100, 0x0100, 0x0504, 0x0504, 0x0908, 0x0908, 0x0d0c, 0x0d0c }, /* 0q */ + { 0x0302, 0x0302, 0x0706, 0x0706, 0x0b0a, 0x0b0a, 0x0f0e, 0x0f0e }, /* 1q */ + + { 0x0100, 0x0100, 0x0100, 0x0100, 0x0908, 0x0908, 0x0908, 0x0908 }, /* 0h */ + { 0x0302, 0x0302, 0x0302, 0x0302, 0x0b0a, 0x0b0a, 0x0b0a, 0x0b0a }, /* 1h */ + { 0x0504, 0x0504, 0x0504, 0x0504, 0x0d0c, 0x0d0c, 0x0d0c, 0x0d0c }, /* 2h */ + { 0x0706, 0x0706, 0x0706, 0x0706, 0x0f0e, 0x0f0e, 0x0f0e, 0x0f0e }, /* 3h */ + + { 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100 }, /* 0w */ + { 0x0302, 0x0302, 0x0302, 0x0302, 0x0302, 0x0302, 0x0302, 0x0302 }, /* 1w */ + { 0x0504, 0x0504, 0x0504, 0x0504, 0x0504, 0x0504, 0x0504, 0x0504 }, /* 2w */ + { 0x0706, 0x0706, 0x0706, 0x0706, 0x0706, 0x0706, 0x0706, 0x0706 }, /* 3w */ + { 0x0908, 0x0908, 0x0908, 0x0908, 0x0908, 0x0908, 0x0908, 0x0908 }, /* 4w */ + { 0x0b0a, 0x0b0a, 0x0b0a, 0x0b0a, 0x0b0a, 0x0b0a, 0x0b0a, 0x0b0a }, /* 5w */ + { 0x0d0c, 0x0d0c, 0x0d0c, 0x0d0c, 0x0d0c, 0x0d0c, 0x0d0c, 0x0d0c }, /* 6w */ + { 0x0f0e, 0x0f0e, 0x0f0e, 0x0f0e, 0x0f0e, 0x0f0e, 0x0f0e, 0x0f0e } /* 7w */ + }, + { // sll_b2l_keys + { 0x0302, 0x0100, 0x0706, 0x0504, 0x0b0a, 0x0908, 0x0f0e, 0x0d0c }, + { 0x8003, 0x0201, 0x0007, 0x0605, 0x040b, 0x0a09, 0x080f, 0x0e0d }, + { 0x8080, 0x0302, 0x0100, 0x0706, 0x0504, 0x0b0a, 0x0908, 0x0f0e }, + { 0x8080, 0x8003, 0x0201, 0x0007, 0x0605, 0x040b, 0x0a09, 0x080f }, + + { 0x8080, 0x8080, 0x0302, 0x0100, 0x0706, 0x0504, 0x0b0a, 0x0908 }, + { 0x8080, 0x8080, 0x8003, 0x0201, 0x0007, 0x0605, 0x040b, 0x0a09 }, + { 0x8080, 0x8080, 0x8080, 0x0302, 0x0100, 0x0706, 0x0504, 0x0b0a }, + { 0x8080, 0x8080, 0x8080, 0x8003, 0x0201, 0x0007, 0x0605, 0x040b }, + + { 0x8080, 0x8080, 0x8080, 0x8080, 0x0302, 0x0100, 0x0706, 0x0504 }, + { 0x8080, 0x8080, 0x8080, 0x8080, 0x8003, 0x0201, 0x0007, 0x0605 }, + { 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x0302, 0x0100, 0x0706 }, + { 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8003, 0x0201, 0x0007 }, + + { 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x0302, 0x0100 }, + { 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8003, 0x0201 }, + { 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x0302 }, + { 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8003 }, + }, + { // sll_l2b_keys + { 0x0100, 0x0302, 0x0504, 0x0706, 0x0908, 0x0b0a, 0x0d0c, 0x0f0e }, + { 0x0201, 0x8003, 0x0605, 0x0007, 0x0a09, 0x040b, 0x0e0d, 0x080f }, + { 0x0302, 0x8080, 0x0706, 0x0100, 0x0b0a, 0x0504, 0x0f0e, 0x0908 }, + { 0x8003, 0x8080, 0x0007, 0x0201, 0x040b, 0x0605, 0x080f, 0x0a09 }, + + { 0x8080, 0x8080, 0x0100, 0x0302, 0x0504, 0x0706, 0x0908, 0x0b0a }, + { 0x8080, 0x8080, 0x0201, 0x8003, 0x0605, 0x0007, 0x0a09, 0x040b }, + { 0x8080, 0x8080, 0x0302, 0x8080, 0x0706, 0x0100, 0x0b0a, 0x0504 }, + { 0x8080, 0x8080, 0x8003, 0x8080, 0x0007, 0x0201, 0x040b, 0x0605 }, + + { 0x8080, 0x8080, 0x8080, 0x8080, 0x0100, 0x0302, 0x0504, 0x0706 }, + { 0x8080, 0x8080, 0x8080, 0x8080, 0x0201, 0x8003, 0x0605, 0x0007 }, + { 0x8080, 0x8080, 0x8080, 0x8080, 0x0302, 0x8080, 0x0706, 0x0100 }, + { 0x8080, 0x8080, 0x8080, 0x8080, 0x8003, 0x8080, 0x0007, 0x0201 }, + + { 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x0100, 0x0302 }, + { 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x0201, 0x8003 }, + { 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x0302, 0x8080 }, + { 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8003, 0x8080 }, + }, + { // srl_b2l_keys + { 0x0302, 0x0100, 0x0706, 0x0504, 0x0b0a, 0x0908, 0x0f0e, 0x0d0c }, + { 0x0201, 0x0007, 0x0605, 0x040b, 0x0a09, 0x080f, 0x0e0d, 0x0c80 }, + { 0x0100, 0x0706, 0x0504, 0x0b0a, 0x0908, 0x0f0e, 0x0d0c, 0x8080 }, + { 0x0007, 0x0605, 0x040b, 0x0a09, 0x080f, 0x0e0d, 0x0c80, 0x8080 }, + + { 0x0706, 0x0504, 0x0b0a, 0x0908, 0x0f0e, 0x0d0c, 0x8080, 0x8080 }, + { 0x0605, 0x040b, 0x0a09, 0x080f, 0x0e0d, 0x0c80, 0x8080, 0x8080 }, + { 0x0504, 0x0b0a, 0x0908, 0x0f0e, 0x0d0c, 0x8080, 0x8080, 0x8080 }, + { 0x040b, 0x0a09, 0x080f, 0x0e0d, 0x0c80, 0x8080, 0x8080, 0x8080 }, + + { 0x0b0a, 0x0908, 0x0f0e, 0x0d0c, 0x8080, 0x8080, 0x8080, 0x8080 }, + { 0x0a09, 0x080f, 0x0e0d, 0x0c80, 0x8080, 0x8080, 0x8080, 0x8080 }, + { 0x0908, 0x0f0e, 0x0d0c, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080 }, + { 0x080f, 0x0e0d, 0x0c80, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080 }, + + { 0x0f0e, 0x0d0c, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080 }, + { 0x0e0d, 0x0c80, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080 }, + { 0x0d0c, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080 }, + { 0x0c80, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080 }, + }, + { // ror_b2l_keys + { 0x0302, 0x0100, 0x0706, 0x0504, 0x0b0a, 0x0908, 0x0f0e, 0x0d0c }, + { 0x0201, 0x0007, 0x0605, 0x040b, 0x0a09, 0x080f, 0x0e0d, 0x0c03 }, + { 0x0100, 0x0706, 0x0504, 0x0b0a, 0x0908, 0x0f0e, 0x0d0c, 0x0302 }, + { 0x0007, 0x0605, 0x040b, 0x0a09, 0x080f, 0x0e0d, 0x0c03, 0x0201 }, + + { 0x0706, 0x0504, 0x0b0a, 0x0908, 0x0f0e, 0x0d0c, 0x0302, 0x0100 }, + { 0x0605, 0x040b, 0x0a09, 0x080f, 0x0e0d, 0x0c03, 0x0201, 0x0007 }, + { 0x0504, 0x0b0a, 0x0908, 0x0f0e, 0x0d0c, 0x0302, 0x0100, 0x0706 }, + { 0x040b, 0x0a09, 0x080f, 0x0e0d, 0x0c03, 0x0201, 0x0007, 0x0605 }, + + { 0x0b0a, 0x0908, 0x0f0e, 0x0d0c, 0x0302, 0x0100, 0x0706, 0x0504 }, + { 0x0a09, 0x080f, 0x0e0d, 0x0c03, 0x0201, 0x0007, 0x0605, 0x040b }, + { 0x0908, 0x0f0e, 0x0d0c, 0x0302, 0x0100, 0x0706, 0x0504, 0x0b0a }, + { 0x080f, 0x0e0d, 0x0c03, 0x0201, 0x0007, 0x0605, 0x040b, 0x0a09 }, + + { 0x0f0e, 0x0d0c, 0x0302, 0x0100, 0x0706, 0x0504, 0x0b0a, 0x0908 }, + { 0x0e0d, 0x0c03, 0x0201, 0x0007, 0x0605, 0x040b, 0x0a09, 0x080f }, + { 0x0d0c, 0x0302, 0x0100, 0x0706, 0x0504, 0x0b0a, 0x0908, 0x0f0e }, + { 0x0c03, 0x0201, 0x0007, 0x0605, 0x040b, 0x0a09, 0x080f, 0x0e0d }, + }, + { // rol_l2b_keys + { 0x0302, 0x0100, 0x0706, 0x0504, 0x0b0a, 0x0908, 0x0f0e, 0x0d0c }, + { 0x0003, 0x0e01, 0x0407, 0x0205, 0x080b, 0x0609, 0x0c0f, 0x0a0d }, + { 0x0100, 0x0f0e, 0x0504, 0x0302, 0x0908, 0x0706, 0x0d0c, 0x0b0a }, + { 0x0e01, 0x0c0f, 0x0205, 0x0003, 0x0609, 0x0407, 0x0a0d, 0x080b }, + + { 0x0f0e, 0x0d0c, 0x0302, 0x0100, 0x0706, 0x0504, 0x0b0a, 0x0908 }, + { 0x0c0f, 0x0a0d, 0x0003, 0x0e01, 0x0407, 0x0205, 0x080b, 0x0609 }, + { 0x0d0c, 0x0b0a, 0x0100, 0x0f0e, 0x0504, 0x0302, 0x0908, 0x0706 }, + { 0x0a0d, 0x080b, 0x0e01, 0x0c0f, 0x0205, 0x0003, 0x0609, 0x0407 }, + + { 0x0b0a, 0x0908, 0x0f0e, 0x0d0c, 0x0302, 0x0100, 0x0706, 0x0504 }, + { 0x080b, 0x0609, 0x0c0f, 0x0a0d, 0x0003, 0x0e01, 0x0407, 0x0205 }, + { 0x0908, 0x0706, 0x0d0c, 0x0b0a, 0x0100, 0x0f0e, 0x0504, 0x0302 }, + { 0x0609, 0x0407, 0x0a0d, 0x080b, 0x0e01, 0x0c0f, 0x0205, 0x0003 }, + + { 0x0706, 0x0504, 0x0b0a, 0x0908, 0x0f0e, 0x0d0c, 0x0302, 0x0100 }, + { 0x0407, 0x0205, 0x080b, 0x0609, 0x0c0f, 0x0a0d, 0x0003, 0x0e01 }, + { 0x0504, 0x0302, 0x0908, 0x0706, 0x0d0c, 0x0b0a, 0x0100, 0x0f0e }, + { 0x0205, 0x0003, 0x0609, 0x0407, 0x0a0d, 0x080b, 0x0e01, 0x0c0f }, + }, + { // ror_l2b_keys + { 0x0302, 0x0100, 0x0706, 0x0504, 0x0b0a, 0x0908, 0x0f0e, 0x0d0c }, + { 0x0205, 0x0003, 0x0609, 0x0407, 0x0a0d, 0x080b, 0x0e01, 0x0c0f }, + { 0x0504, 0x0302, 0x0908, 0x0706, 0x0d0c, 0x0b0a, 0x0100, 0x0f0e }, + { 0x0407, 0x0205, 0x080b, 0x0609, 0x0c0f, 0x0a0d, 0x0003, 0x0e01 }, + + { 0x0706, 0x0504, 0x0b0a, 0x0908, 0x0f0e, 0x0d0c, 0x0302, 0x0100 }, + { 0x0609, 0x0407, 0x0a0d, 0x080b, 0x0e01, 0x0c0f, 0x0205, 0x0003 }, + { 0x0908, 0x0706, 0x0d0c, 0x0b0a, 0x0100, 0x0f0e, 0x0504, 0x0302 }, + { 0x080b, 0x0609, 0x0c0f, 0x0a0d, 0x0003, 0x0e01, 0x0407, 0x0205 }, + + { 0x0b0a, 0x0908, 0x0f0e, 0x0d0c, 0x0302, 0x0100, 0x0706, 0x0504 }, + { 0x0a0d, 0x080b, 0x0e01, 0x0c0f, 0x0205, 0x0003, 0x0609, 0x0407 }, + { 0x0d0c, 0x0b0a, 0x0100, 0x0f0e, 0x0504, 0x0302, 0x0908, 0x0706 }, + { 0x0c0f, 0x0a0d, 0x0003, 0x0e01, 0x0407, 0x0205, 0x080b, 0x0609 }, + + { 0x0f0e, 0x0d0c, 0x0302, 0x0100, 0x0706, 0x0504, 0x0b0a, 0x0908 }, + { 0x0e01, 0x0c0f, 0x0205, 0x0003, 0x0609, 0x0407, 0x0a0d, 0x080b }, + { 0x0100, 0x0f0e, 0x0504, 0x0302, 0x0908, 0x0706, 0x0d0c, 0x0b0a }, + { 0x0003, 0x0e01, 0x0407, 0x0205, 0x080b, 0x0609, 0x0c0f, 0x0a0d }, + }, + { // qr_lut + { 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff }, + { 0xffff, 0xff00, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff }, + { 0xffff, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff }, + { 0xff00, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff }, + + { 0x0000, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + { 0x0000, 0x0000, 0xffff, 0xff00, 0xffff, 0xffff, 0xffff, 0xffff }, + { 0x0000, 0x0000, 0xffff, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff }, + { 0x0000, 0x0000, 0xff00, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff }, + + { 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff }, + { 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0xff00, 0xffff, 0xffff }, + { 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0x0000, 0xffff, 0xffff }, + { 0x0000, 0x0000, 0x0000, 0x0000, 0xff00, 0x0000, 0xffff, 0xffff }, + + { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0xffff }, + { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0xff00 }, + { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0x0000 }, + { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xff00, 0x0000 } + }, + { // bdls_lut - mask to denote which part of the vector to load/store. + { 0x0000, 0xff00, 0x0000, 0x0000 }, // B + { 0x0000, 0xffff, 0x0000, 0x0000 }, // S + { 0xffff, 0xffff, 0x0000, 0x0000 }, // L + { 0xffff, 0xffff, 0xffff, 0xffff } // D + }, + { // word_reverse + 0x0203, 0x0001, 0x0607, 0x0405, 0x0a0b, 0x0809, 0x0e0f, 0x0c0d + } +}; + +#if !(defined(__SSSE3__) || defined(_MSC_VER)) +// TODO: Highly optimized. More of a stopgap measure. +static inline rsp_vec_t sse2_pshufb(rsp_vec_t v, const UINT16 *keys) +{ + UINT8 dest[16]; + UINT8 temp[16]; + + _mm_storeu_si128((rsp_vec_t *) temp, v); + + for (UINT32 j = 0; j < 8; j++) + { + UINT16 key = keys[j]; + UINT8 key_hi = key >> 8; + UINT8 key_lo = key >> 0; + + dest[(j << 1) + 1] = key_hi == 0x80 ? 0x00 : temp[key_hi]; + dest[(j << 1) + 0] = key_lo == 0x80 ? 0x00 : temp[key_lo]; + } + + return _mm_loadu_si128((rsp_vec_t *) dest); +} + +rsp_vec_t rsp_cop2::vec_load_and_shuffle_operand(const UINT16* src, UINT32 element) +{ + if (element >= 8) // element => 0w ... 7w + { + UINT16 word_lo; + + memcpy(&word_lo, src + (element - 8), sizeof(word_lo)); + UINT64 dword = word_lo | ((UINT32) word_lo << 16); + + return _mm_shuffle_epi32(_mm_loadl_epi64((rsp_vec_t*) &dword), _MM_SHUFFLE(0,0,0,0)); + } + else if (element >= 4) // element => 0h ... 3h + { + UINT16 word_lo; + UINT16 word_hi; + + memcpy(&word_hi, src + element - 0, sizeof(word_hi)); + memcpy(&word_lo, src + element - 4, sizeof(word_lo)); + UINT64 dword = word_lo | ((UINT32) word_hi << 16); + + rsp_vec_t v = _mm_loadl_epi64((rsp_vec_t*) &dword); + v = _mm_shufflelo_epi16(v, _MM_SHUFFLE(1,1,0,0)); + return _mm_shuffle_epi32(v, _MM_SHUFFLE(1,1,0,0)); + } + else if (element >= 2) // element => 0q ... 1q + { + rsp_vec_t v = vec_load_unshuffled_operand(src); + + if (element == 2) { + v = _mm_shufflelo_epi16(v, _MM_SHUFFLE(3,3,1,1)); + v = _mm_shufflehi_epi16(v, _MM_SHUFFLE(3,3,1,1)); + } + else + { + v = _mm_shufflelo_epi16(v, _MM_SHUFFLE(2,2,0,0)); + v = _mm_shufflehi_epi16(v, _MM_SHUFFLE(2,2,0,0)); + } + + return v; + } + + return vec_load_unshuffled_operand(src); +} +#else +rsp_vec_t rsp_cop2::vec_load_and_shuffle_operand(const UINT16* src, UINT32 element) +{ + rsp_vec_t operand = _mm_load_si128((rsp_vec_t*) src); + rsp_vec_t key = _mm_load_si128((rsp_vec_t*) m_vec_helpers.shuffle_keys[element]); + + return _mm_shuffle_epi8(operand, key); +} +#endif +// +// SSSE3+ accelerated loads for group I. Byteswap big-endian to 2-byte +// little-endian vector. Start at vector element offset, discarding any +// wraparound as necessary. +// +// TODO: Reverse-engineer what happens when loads to vector elements must +// wraparound. Do we just discard the data, as below, or does the +// data effectively get rotated around the edge of the vector? +// +void rsp_cop2::vec_load_group1(UINT32 addr, UINT32 element, UINT16 *regp, rsp_vec_t reg, rsp_vec_t dqm) +{ + UINT32 offset = addr & 0x7; + UINT32 ror = offset - element; + + // Always load in 8-byte chunks to emulate wraparound. + rsp_vec_t data; + if (offset) { + UINT32 aligned_addr_lo = addr & ~0x7; + UINT32 aligned_addr_hi = (aligned_addr_lo + 8) & 0xFFF; + + data = _mm_loadl_epi64((rsp_vec_t *) (m_rsp.get_dmem() + aligned_addr_lo)); + rsp_vec_t temp = _mm_loadl_epi64((rsp_vec_t *) (m_rsp.get_dmem() + aligned_addr_hi)); + data = _mm_unpacklo_epi64(data, temp); + } + else + { + data = _mm_loadl_epi64((rsp_vec_t *) (m_rsp.get_dmem() + addr)); + } + + // Shift the DQM up to the point where we mux in the data. +#if !(defined(__SSSE3__) || defined(_MSC_VER)) + dqm = sse2_pshufb(dqm, m_vec_helpers.sll_b2l_keys[element]); +#else + rsp_vec_t ekey = _mm_load_si128((rsp_vec_t *) (m_vec_helpers.sll_b2l_keys[element])); + dqm = _mm_shuffle_epi8(dqm, ekey); +#endif + + // Align the data to the DQM so we can mask it in. +#if !(defined(__SSSE3__) || defined(_MSC_VER)) + data = sse2_pshufb(data, m_vec_helpers.ror_b2l_keys[ror & 0xF]); +#else + ekey = _mm_load_si128((rsp_vec_t *) (m_vec_helpers.ror_b2l_keys[ror & 0xF])); + data = _mm_shuffle_epi8(data, ekey); +#endif + + // Mask and mux in the data. +#if (defined(__SSE4_1__) || defined(_MSC_VER)) + reg = _mm_blendv_epi8(reg, data, dqm); +#else + data = _mm_and_si128(dqm, data); + reg = _mm_andnot_si128(dqm, reg); + reg = _mm_or_si128(data, reg); +#endif + + _mm_store_si128((rsp_vec_t *) regp, reg); +} + +// +// SSSE3+ accelerated loads for group II. +// +// TODO: Reverse-engineer what happens when loads to vector elements must +// wraparound. Do we just discard the data, as below, or does the +// data effectively get rotated around the edge of the vector? +// +// TODO: Reverse-engineer what happens when element != 0. +// +void rsp_cop2::vec_load_group2(UINT32 addr, UINT32 element, UINT16 *regp, rsp_vec_t reg, rsp_vec_t dqm, rsp_mem_request_type request_type) { + UINT32 offset = addr & 0x7; + rsp_vec_t data; + + // Always load in 8-byte chunks to emulate wraparound. + if (offset) { + UINT32 aligned_addr_lo = addr & ~0x7; + UINT32 aligned_addr_hi = (aligned_addr_lo + 8) & 0xFFF; + UINT64 datalow, datahigh; + + memcpy(&datalow, m_rsp.get_dmem() + aligned_addr_lo, sizeof(datalow)); + memcpy(&datahigh, m_rsp.get_dmem() + aligned_addr_hi, sizeof(datahigh)); + + // TODO: Test for endian issues? + datahigh >>= ((8 - offset) << 3); + datalow <<= (offset << 3); + datalow = datahigh | datalow; + + data = _mm_loadl_epi64((rsp_vec_t *) &datalow); + } + else + { + data = _mm_loadl_epi64((rsp_vec_t *) (m_rsp.get_dmem() + addr)); + } + + // "Unpack" the data. + rsp_vec_t zero = _mm_setzero_si128(); + data = _mm_unpacklo_epi8(zero, data); + + if (request_type != RSP_MEM_REQUEST_PACK) + { + data = _mm_srli_epi16(data, 1); + } + + data = _mm_shufflehi_epi16(data, _MM_SHUFFLE(0, 1, 2, 3)); + data = _mm_shufflelo_epi16(data, _MM_SHUFFLE(0, 1, 2, 3)); + + _mm_store_si128((rsp_vec_t *) regp, data); +} + +// +// SSSE3+ accelerated loads for group IV. Byteswap big-endian to 2-byte +// little-endian vector. Stop loading at quadword boundaries. +// +// TODO: Reverse-engineer what happens when loads from vector elements +// must wraparound (i.e., the address offset is small, starting +// element is large). +// +void rsp_cop2::vec_load_group4(UINT32 addr, UINT32 element, UINT16 *regp, rsp_vec_t reg, rsp_vec_t dqm, rsp_mem_request_type request_type) +{ + UINT32 aligned_addr = addr & 0xFF0; + UINT32 offset = addr & 0xF; + static UINT32 call_count = 0; + + rsp_vec_t data = _mm_load_si128((rsp_vec_t *) (m_rsp.get_dmem() + aligned_addr)); + + UINT32 ror; + if (request_type == RSP_MEM_REQUEST_QUAD) + { + ror = 16 - element + offset; + } + else + { + // TODO: How is this adjusted for LRV when e != 0? + dqm = _mm_cmpeq_epi8(_mm_setzero_si128(), dqm); + ror = 16 - offset; + } + +#if !(defined(__SSSE3__) || defined(_MSC_VER)) + data = sse2_pshufb(data, m_vec_helpers.ror_b2l_keys[ror & 0xF]); + dqm = sse2_pshufb(dqm, m_vec_helpers.ror_b2l_keys[ror & 0xF]); +#else + rsp_vec_t dkey = _mm_load_si128((rsp_vec_t *) (m_vec_helpers.ror_b2l_keys[ror & 0xF])); + data = _mm_shuffle_epi8(data, dkey); + dqm = _mm_shuffle_epi8(dqm, dkey); +#endif + + // Mask and mux in the data. +#if (defined(__SSE4_1__) || defined(_MSC_VER)) + data = _mm_blendv_epi8(reg, data, dqm); +#else + data = _mm_and_si128(dqm, data); + reg = _mm_andnot_si128(dqm, reg); + data = _mm_or_si128(data, reg); +#endif + + _mm_store_si128((rsp_vec_t *) regp, data); + + call_count++; +} + +// +// SSE3+ accelerated stores for group I. Byteswap 2-byte little-endian +// vector back to big-endian. Start at vector element offset, wrapping +// around the edge of the vector as necessary. +// +// TODO: Reverse-engineer what happens when stores from vector elements +// must wraparound. Do we just stop storing the data, or do we +// continue storing from the front of the vector, as below? +// +void rsp_cop2::vec_store_group1(UINT32 addr, UINT32 element, UINT16 *regp, rsp_vec_t reg, rsp_vec_t dqm) +{ + UINT32 offset = addr & 0x7; + UINT32 ror = element - offset; + + // Shift the DQM up to the point where we mux in the data. +#if !(defined(__SSSE3__) || defined(_MSC_VER)) + dqm = sse2_pshufb(dqm, m_vec_helpers.sll_l2b_keys[offset]); +#else + rsp_vec_t ekey = _mm_load_si128((rsp_vec_t *) (m_vec_helpers.sll_l2b_keys[offset])); + dqm = _mm_shuffle_epi8(dqm, ekey); +#endif + + // Rotate the reg to align with the DQM. +#if !(defined(__SSSE3__) || defined(_MSC_VER)) + reg = sse2_pshufb(reg, m_vec_helpers.ror_l2b_keys[ror & 0xF]); +#else + ekey = _mm_load_si128((rsp_vec_t *) (m_vec_helpers.ror_l2b_keys[ror & 0xF])); + reg = _mm_shuffle_epi8(reg, ekey); +#endif + + // Always load in 8-byte chunks to emulate wraparound. + rsp_vec_t data; + if (offset) + { + UINT32 aligned_addr_lo = addr & ~0x7; + UINT32 aligned_addr_hi = (aligned_addr_lo + 8) & 0xFFF; + + data = _mm_loadl_epi64((rsp_vec_t *) (m_rsp.get_dmem() + aligned_addr_lo)); + rsp_vec_t temp = _mm_loadl_epi64((rsp_vec_t *) (m_rsp.get_dmem() + aligned_addr_hi)); + data = _mm_unpacklo_epi64(data, temp); + + // Mask and mux in the data. +#if (defined(__SSE4_1__) || defined(_MSC_VER)) + data = _mm_blendv_epi8(data, reg, dqm); +#else + data = _mm_andnot_si128(dqm, data); + reg = _mm_and_si128(dqm, reg); + data = _mm_or_si128(data, reg); +#endif + + _mm_storel_epi64((rsp_vec_t *) (m_rsp.get_dmem() + aligned_addr_lo), data); + + data = _mm_srli_si128(data, 8); + _mm_storel_epi64((rsp_vec_t *) (m_rsp.get_dmem() + aligned_addr_hi), data); + } + else + { + data = _mm_loadl_epi64((rsp_vec_t *) (m_rsp.get_dmem() + addr)); + + // Mask and mux in the data. +#if (defined(__SSE4_1__) || defined(_MSC_VER)) + data = _mm_blendv_epi8(data, reg, dqm); +#else + data = _mm_andnot_si128(dqm, data); + reg = _mm_and_si128(dqm, reg); + data = _mm_or_si128(data, reg); +#endif + + _mm_storel_epi64((rsp_vec_t *) (m_rsp.get_dmem() + addr), data); + } +} + +// +// SSE3+ accelerated stores for group II. Byteswap 2-byte little-endian +// vector back to big-endian. Start at vector element offset, wrapping +// around the edge of the vector as necessary. +// +// TODO: Reverse-engineer what happens when stores from vector elements +// must wraparound. Do we just stop storing the data, or do we +// continue storing from the front of the vector, as below? +// +// TODO: Reverse-engineer what happens when element != 0. +// +void rsp_cop2::vec_store_group2(UINT32 addr, UINT32 element, UINT16 *regp, rsp_vec_t reg, rsp_vec_t dqm, rsp_mem_request_type request_type) { + // "Pack" the data. + if (request_type != RSP_MEM_REQUEST_PACK) + { + reg = _mm_slli_epi16(reg, 1); + } + + reg = _mm_srai_epi16(reg, 8); + reg = _mm_packs_epi16(reg, reg); + +#if !(defined(__SSSE3__) || defined(_MSC_VER)) + reg = sse2_pshufb(reg, m_vec_helpers.word_reverse); +#else + rsp_vec_t dkey = _mm_load_si128((rsp_vec_t *) (m_vec_helpers.word_reverse)); + reg = _mm_shuffle_epi8(reg, dkey); +#endif + + // TODO: Always store in 8-byte chunks to emulate wraparound. + _mm_storel_epi64((rsp_vec_t *) (m_rsp.get_dmem() + addr), reg); +} + +// +// SSE3+ accelerated stores for group IV. Byteswap 2-byte little-endian +// vector back to big-endian. Stop storing at quadword boundaries. +// +void rsp_cop2::vec_store_group4(UINT32 addr, UINT32 element, UINT16 *regp, rsp_vec_t reg, rsp_vec_t dqm, rsp_mem_request_type request_type) { + UINT32 aligned_addr = addr & 0xFF0; + UINT32 offset = addr & 0xF; + UINT32 rol = offset; + + rsp_vec_t data = _mm_load_si128((rsp_vec_t *) (m_rsp.get_dmem() + aligned_addr)); + + if (request_type == RSP_MEM_REQUEST_QUAD) + { + rol -= element; + } + else + { + // TODO: How is this adjusted for SRV when e != 0? + dqm = _mm_cmpeq_epi8(_mm_setzero_si128(), dqm); + } + +#if !(defined(__SSSE3__) || defined(_MSC_VER)) + reg = sse2_pshufb(reg, m_vec_helpers.rol_l2b_keys[rol & 0xF]); +#else + rsp_vec_t ekey = _mm_load_si128((rsp_vec_t *) (m_vec_helpers.rol_l2b_keys[rol & 0xF])); + reg = _mm_shuffle_epi8(reg, ekey); +#endif + + // Mask and mux out the data, write. +#if (defined(__SSE4_1__) || defined(_MSC_VER)) + data = _mm_blendv_epi8(data, reg, dqm); +#else + reg = _mm_and_si128(dqm, reg); + data = _mm_andnot_si128(dqm, data); + data = _mm_or_si128(data, reg); +#endif + + _mm_store_si128((rsp_vec_t *) (m_rsp.get_dmem() + aligned_addr), data); +} +#endif extern offs_t rsp_dasm_one(char *buffer, offs_t pc, UINT32 op); @@ -100,6 +668,7 @@ extern offs_t rsp_dasm_one(char *buffer, offs_t pc, UINT32 op); VREG_S(VDREG, 7) = m_vres[7]; \ } +#if !USE_SIMD static const int vector_elements_2[16][8] = { { 0, 1, 2, 3, 4, 5, 6, 7 }, // none @@ -119,6 +688,7 @@ static const int vector_elements_2[16][8] = { 6, 6, 6, 6, 6, 6, 6, 6 }, // 6 { 7, 7, 7, 7, 7, 7, 7, 7 }, // 7 }; +#endif rsp_cop2::rsp_cop2(rsp_device &rsp, running_machine &machine) : m_rsp(rsp) @@ -131,6 +701,13 @@ rsp_cop2::rsp_cop2(rsp_device &rsp, running_machine &machine) memset(m_v, 0, sizeof(m_v)); memset(m_vflag, 0, sizeof(m_vflag)); memset(m_accum, 0, sizeof(m_accum)); +#if USE_SIMD + memset(&m_acc, 0, sizeof(m_acc)); + memset(&m_flags, 0, sizeof(aligned_rsp_2vect_t) * 3); + m_div_out = 0; + m_div_in = 0; +#endif + m_rspcop2_state = (internal_rspcop2_state *)rsp.m_cache.alloc_near(sizeof(internal_rspcop2_state)); } rsp_cop2::~rsp_cop2() @@ -278,14 +855,16 @@ void rsp_cop2::state_string_export(const int index, std::string &str) void rsp_cop2::handle_lwc2(UINT32 op) { + int base = (op >> 21) & 0x1f; +#if !USE_SIMD 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; +#endif switch ((op >> 11) & 0x1f) { @@ -298,8 +877,14 @@ void rsp_cop2::handle_lwc2(UINT32 op) // // Load 1 byte to vector byte index + //printf("LBV "); +#if USE_SIMD + vec_lbdlsv_sbdlsv(op, m_rsp.m_rsp_state->r[base]); +#else ea = (base) ? m_rsp.m_rsp_state->r[base] + offset : offset; VREG_B(dest, index) = m_rsp.READ8(ea); +#endif + // break; } case 0x01: /* LSV */ @@ -311,6 +896,10 @@ void rsp_cop2::handle_lwc2(UINT32 op) // // Loads 2 bytes starting from vector byte index + //printf("LSV "); +#if USE_SIMD + vec_lbdlsv_sbdlsv(op, m_rsp.m_rsp_state->r[base]); +#else ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 2) : (offset * 2); end = index + 2; @@ -320,6 +909,8 @@ void rsp_cop2::handle_lwc2(UINT32 op) VREG_B(dest, i) = m_rsp.READ8(ea); ea++; } +#endif + // break; } case 0x02: /* LLV */ @@ -331,6 +922,10 @@ void rsp_cop2::handle_lwc2(UINT32 op) // // Loads 4 bytes starting from vector byte index + //printf("LLV "); +#if USE_SIMD + vec_lbdlsv_sbdlsv(op, m_rsp.m_rsp_state->r[base]); +#else ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 4) : (offset * 4); end = index + 4; @@ -340,6 +935,8 @@ void rsp_cop2::handle_lwc2(UINT32 op) VREG_B(dest, i) = m_rsp.READ8(ea); ea++; } +#endif + // break; } case 0x03: /* LDV */ @@ -351,6 +948,10 @@ void rsp_cop2::handle_lwc2(UINT32 op) // // Loads 8 bytes starting from vector byte index + //printf("LDV "); +#if USE_SIMD + vec_lbdlsv_sbdlsv(op, m_rsp.m_rsp_state->r[base]); +#else ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 8) : (offset * 8); end = index + 8; @@ -360,6 +961,8 @@ void rsp_cop2::handle_lwc2(UINT32 op) VREG_B(dest, i) = m_rsp.READ8(ea); ea++; } +#endif + // break; } case 0x04: /* LQV */ @@ -371,6 +974,10 @@ void rsp_cop2::handle_lwc2(UINT32 op) // // Loads up to 16 bytes starting from vector byte index + //printf("LQV "); +#if USE_SIMD + vec_lqrv_sqrv(op, m_rsp.m_rsp_state->r[base]); +#else ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); end = index + (16 - (ea & 0xf)); @@ -381,6 +988,8 @@ void rsp_cop2::handle_lwc2(UINT32 op) VREG_B(dest, i) = m_rsp.READ8(ea); ea++; } +#endif + // break; } case 0x05: /* LRV */ @@ -392,6 +1001,10 @@ void rsp_cop2::handle_lwc2(UINT32 op) // // Stores up to 16 bytes starting from right side until 16-byte boundary + //printf("LRV "); +#if USE_SIMD + vec_lqrv_sqrv(op, m_rsp.m_rsp_state->r[base]); +#else ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); index = 16 - ((ea & 0xf) - index); @@ -403,6 +1016,8 @@ void rsp_cop2::handle_lwc2(UINT32 op) VREG_B(dest, i) = m_rsp.READ8(ea); ea++; } +#endif + // break; } case 0x06: /* LPV */ @@ -414,12 +1029,18 @@ void rsp_cop2::handle_lwc2(UINT32 op) // // Loads a byte as the upper 8 bits of each element + //printf("LPV "); +#if USE_SIMD + vec_lfhpuv_sfhpuv(op, m_rsp.m_rsp_state->r[base]); +#else ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 8) : (offset * 8); for (i=0; i < 8; i++) { VREG_S(dest, i) = m_rsp.READ8(ea + (((16-index) + i) & 0xf)) << 8; } +#endif + // break; } case 0x07: /* LUV */ @@ -431,12 +1052,18 @@ void rsp_cop2::handle_lwc2(UINT32 op) // // Loads a byte as the bits 14-7 of each element + //printf("LUV "); +#if USE_SIMD + vec_lfhpuv_sfhpuv(op, m_rsp.m_rsp_state->r[base]); +#else ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 8) : (offset * 8); for (i=0; i < 8; i++) { VREG_S(dest, i) = m_rsp.READ8(ea + (((16-index) + i) & 0xf)) << 7; } +#endif + // break; } case 0x08: /* LHV */ @@ -448,12 +1075,18 @@ void rsp_cop2::handle_lwc2(UINT32 op) // // Loads a byte as the bits 14-7 of each element, with 2-byte stride + //printf("LHV "); +#if USE_SIMD + vec_lfhpuv_sfhpuv(op, m_rsp.m_rsp_state->r[base]); +#else ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); for (i=0; i < 8; i++) { VREG_S(dest, i) = m_rsp.READ8(ea + (((16-index) + (i<<1)) & 0xf)) << 7; } +#endif + // break; } case 0x09: /* LFV */ @@ -465,6 +1098,10 @@ void rsp_cop2::handle_lwc2(UINT32 op) // // Loads a byte as the bits 14-7 of upper or lower quad, with 4-byte stride + //printf("LFV "); +#if USE_SIMD + vec_lfhpuv_sfhpuv(op, m_rsp.m_rsp_state->r[base]); +#else ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); // not sure what happens if 16-byte boundary is crossed... @@ -476,6 +1113,8 @@ void rsp_cop2::handle_lwc2(UINT32 op) VREG_S(dest, i) = m_rsp.READ8(ea) << 7; ea += 4; } +#endif + // break; } case 0x0a: /* LWV */ @@ -488,6 +1127,9 @@ void rsp_cop2::handle_lwc2(UINT32 op) // Loads the full 128-bit vector starting from vector byte index and wrapping to index 0 // after byte index 15 + //printf("LWV "); +#if USE_SIMD +#else ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); end = (16 - index) + 16; @@ -497,6 +1139,8 @@ void rsp_cop2::handle_lwc2(UINT32 op) VREG_B(dest, i & 0xf) = m_rsp.READ8(ea); ea += 4; } +#endif + // break; } case 0x0b: /* LTV */ @@ -510,20 +1154,27 @@ void rsp_cop2::handle_lwc2(UINT32 op) // FIXME: has a small problem with odd indices - int element; - int vs = dest; - int ve = dest + 8; + //printf("LTV "); +#if 0 +#else + INT32 index = (op >> 7) & 0xf; + INT32 offset = (op & 0x7f); + if (offset & 0x40) + offset |= 0xffffffc0; + + INT32 vs = (op >> 16) & 0x1f; + INT32 ve = vs + 8; if (ve > 32) ve = 32; - element = 7 - (index >> 1); + INT32 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); + UINT32 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++) + for (INT32 i = vs; i < ve; i++) { element = ((8 - (index >> 1) + (i-vs)) << 1); VREG_B(i, (element & 0xf)) = m_rsp.READ8(ea); @@ -531,6 +1182,8 @@ void rsp_cop2::handle_lwc2(UINT32 op) ea += 2; } +#endif + // break; } @@ -549,15 +1202,17 @@ void rsp_cop2::handle_lwc2(UINT32 op) void rsp_cop2::handle_swc2(UINT32 op) { + int base = (op >> 21) & 0x1f; +#if !USE_SIMD 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; +#endif switch ((op >> 11) & 0x1f) { @@ -570,8 +1225,14 @@ void rsp_cop2::handle_swc2(UINT32 op) // // Stores 1 byte from vector byte index + //printf("SBV "); +#if USE_SIMD + vec_lbdlsv_sbdlsv(op, m_rsp.m_rsp_state->r[base]); +#else ea = (base) ? m_rsp.m_rsp_state->r[base] + offset : offset; m_rsp.WRITE8(ea, VREG_B(dest, index)); +#endif + // break; } case 0x01: /* SSV */ @@ -583,6 +1244,10 @@ void rsp_cop2::handle_swc2(UINT32 op) // // Stores 2 bytes starting from vector byte index + //printf("SSV "); +#if USE_SIMD + vec_lbdlsv_sbdlsv(op, m_rsp.m_rsp_state->r[base]); +#else ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 2) : (offset * 2); end = index + 2; @@ -592,6 +1257,8 @@ void rsp_cop2::handle_swc2(UINT32 op) m_rsp.WRITE8(ea, VREG_B(dest, i)); ea++; } +#endif + // break; } case 0x02: /* SLV */ @@ -603,6 +1270,10 @@ void rsp_cop2::handle_swc2(UINT32 op) // // Stores 4 bytes starting from vector byte index + //printf("SLV "); +#if USE_SIMD + vec_lbdlsv_sbdlsv(op, m_rsp.m_rsp_state->r[base]); +#else ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 4) : (offset * 4); end = index + 4; @@ -612,6 +1283,8 @@ void rsp_cop2::handle_swc2(UINT32 op) m_rsp.WRITE8(ea, VREG_B(dest, i)); ea++; } +#endif + // break; } case 0x03: /* SDV */ @@ -623,6 +1296,10 @@ void rsp_cop2::handle_swc2(UINT32 op) // // Stores 8 bytes starting from vector byte index + //printf("SDV "); +#if USE_SIMD + vec_lbdlsv_sbdlsv(op, m_rsp.m_rsp_state->r[base]); +#else ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 8) : (offset * 8); end = index + 8; @@ -632,6 +1309,8 @@ void rsp_cop2::handle_swc2(UINT32 op) m_rsp.WRITE8(ea, VREG_B(dest, i)); ea++; } +#endif + // break; } case 0x04: /* SQV */ @@ -643,6 +1322,10 @@ void rsp_cop2::handle_swc2(UINT32 op) // // Stores up to 16 bytes starting from vector byte index until 16-byte boundary + //printf("SQV "); +#if USE_SIMD + vec_lqrv_sqrv(op, m_rsp.m_rsp_state->r[base]); +#else ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); end = index + (16 - (ea & 0xf)); @@ -652,6 +1335,8 @@ void rsp_cop2::handle_swc2(UINT32 op) m_rsp.WRITE8(ea, VREG_B(dest, i & 0xf)); ea++; } +#endif + // break; } case 0x05: /* SRV */ @@ -663,6 +1348,10 @@ void rsp_cop2::handle_swc2(UINT32 op) // // Stores up to 16 bytes starting from right side until 16-byte boundary + //printf("SRV "); +#if USE_SIMD + vec_lqrv_sqrv(op, m_rsp.m_rsp_state->r[base]); +#else int o; ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); @@ -675,6 +1364,8 @@ void rsp_cop2::handle_swc2(UINT32 op) m_rsp.WRITE8(ea, VREG_B(dest, ((i + o) & 0xf))); ea++; } +#endif + // break; } case 0x06: /* SPV */ @@ -686,6 +1377,10 @@ void rsp_cop2::handle_swc2(UINT32 op) // // Stores upper 8 bits of each element + //printf("SPV "); +#if USE_SIMD + vec_lfhpuv_sfhpuv(op, m_rsp.m_rsp_state->r[base]); +#else ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 8) : (offset * 8); end = index + 8; @@ -701,6 +1396,8 @@ void rsp_cop2::handle_swc2(UINT32 op) } ea++; } +#endif + // break; } case 0x07: /* SUV */ @@ -712,6 +1409,10 @@ void rsp_cop2::handle_swc2(UINT32 op) // // Stores bits 14-7 of each element + //printf("SUV "); +#if USE_SIMD + vec_lfhpuv_sfhpuv(op, m_rsp.m_rsp_state->r[base]); +#else ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 8) : (offset * 8); end = index + 8; @@ -727,6 +1428,8 @@ void rsp_cop2::handle_swc2(UINT32 op) } ea++; } +#endif + // break; } case 0x08: /* SHV */ @@ -738,6 +1441,10 @@ void rsp_cop2::handle_swc2(UINT32 op) // // Stores bits 14-7 of each element, with 2-byte stride + //printf("SHV "); +#if USE_SIMD + vec_lfhpuv_sfhpuv(op, m_rsp.m_rsp_state->r[base]); +#else ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); for (i=0; i < 8; i++) @@ -748,6 +1455,8 @@ void rsp_cop2::handle_swc2(UINT32 op) m_rsp.WRITE8(ea, d); ea += 2; } +#endif + // break; } case 0x09: /* SFV */ @@ -761,6 +1470,10 @@ void rsp_cop2::handle_swc2(UINT32 op) // FIXME: only works for index 0 and index 8 + //printf("SFV "); +#if USE_SIMD + vec_lfhpuv_sfhpuv(op, m_rsp.m_rsp_state->r[base]); +#else ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); eaoffset = ea & 0xf; @@ -773,6 +1486,8 @@ void rsp_cop2::handle_swc2(UINT32 op) m_rsp.WRITE8(ea + (eaoffset & 0xf), VREG_S(dest, i) >> 7); eaoffset += 4; } +#endif + // break; } case 0x0a: /* SWV */ @@ -785,6 +1500,9 @@ void rsp_cop2::handle_swc2(UINT32 op) // Stores the full 128-bit vector starting from vector byte index and wrapping to index 0 // after byte index 15 + //printf("SWV "); +#if USE_SIMD +#else ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); eaoffset = ea & 0xf; @@ -797,6 +1515,8 @@ void rsp_cop2::handle_swc2(UINT32 op) m_rsp.WRITE8(ea + (eaoffset & 0xf), VREG_B(dest, i & 0xf)); eaoffset++; } +#endif + // break; } case 0x0b: /* STV */ @@ -808,25 +1528,34 @@ void rsp_cop2::handle_swc2(UINT32 op) // // Stores one element from maximum of 8 vectors, while incrementing element index - int element; - int vs = dest; - int ve = dest + 8; + //printf("STV "); +#if 0 +#else + INT32 index = (op >> 7) & 0xf; + INT32 offset = (op & 0x7f); + if (offset & 0x40) + offset |= 0xffffffc0; + + INT32 vs = (op >> 16) & 0x1f; + INT32 ve = vs + 8; if (ve > 32) ve = 32; - element = 8 - (index >> 1); + INT32 element = 8 - (index >> 1); - ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); + UINT32 ea = (base) ? m_rsp.m_rsp_state->r[base] + (offset * 16) : (offset * 16); - eaoffset = (ea & 0xf) + (element * 2); + INT32 eaoffset = (ea & 0xf) + (element * 2); ea &= ~0xf; - for (i=vs; i < ve; i++) + for (INT32 i = vs; i < ve; i++) { m_rsp.WRITE16(ea + (eaoffset & 0xf), VREG_S(i, element & 0x7)); eaoffset += 2; element++; } +#endif + // break; } @@ -904,7 +1633,9 @@ UINT16 rsp_cop2::SATURATE_ACCUM(int accum, int slice, UINT16 negative, UINT16 po void rsp_cop2::handle_vector_ops(UINT32 op) { +#if !USE_SIMD int i; +#endif // Opcode legend: // E = VS2 element type @@ -923,6 +1654,20 @@ void rsp_cop2::handle_vector_ops(UINT32 op) // // Multiplies signed integer by signed integer * 2 + //printf("MULF "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + rsp_vec_t acc_lo, acc_mid, acc_hi; + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_vmulf_vmulu(op, vs, vt_shuffle, vec_zero(), &acc_lo, &acc_mid, &acc_hi); + + write_acc_lo(acc, acc_lo); + write_acc_mid(acc, acc_mid); + write_acc_hi(acc, acc_hi); +#else for (i=0; i < 8; i++) { INT32 s1 = (INT32)(INT16)VREG_S(VS1REG, i); @@ -947,8 +1692,10 @@ void rsp_cop2::handle_vector_ops(UINT32 op) } } WRITEBACK_RESULT(); - +#endif + // break; + } case 0x01: /* VMULU */ @@ -959,6 +1706,20 @@ void rsp_cop2::handle_vector_ops(UINT32 op) // ------------------------------------------------------ // + //printf("MULU "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + rsp_vec_t acc_lo, acc_mid, acc_hi; + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_vmulf_vmulu(op, vs, vt_shuffle, vec_zero(), &acc_lo, &acc_mid, &acc_hi); + + write_acc_lo(acc, acc_lo); + write_acc_mid(acc, acc_mid); + write_acc_hi(acc, acc_hi); +#else for (i=0; i < 8; i++) { INT32 s1 = (INT32)(INT16)VREG_S(VS1REG, i); @@ -985,6 +1746,8 @@ void rsp_cop2::handle_vector_ops(UINT32 op) } } WRITEBACK_RESULT(); +#endif + // break; } @@ -999,6 +1762,24 @@ void rsp_cop2::handle_vector_ops(UINT32 op) // Stores the higher 16 bits of the 32-bit result to accumulator // The low slice of accumulator is stored into destination element + //printf("MUDL "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + rsp_vec_t acc_lo, acc_mid, acc_hi; + + acc_lo = read_acc_lo(acc); + acc_mid = read_acc_mid(acc); + acc_hi = read_acc_hi(acc); + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_vmadl_vmudl(op, vs, vt_shuffle, vec_zero(), &acc_lo, &acc_mid, &acc_hi); + + write_acc_lo(acc, acc_lo); + write_acc_mid(acc, acc_mid); + write_acc_hi(acc, acc_hi); +#else for (i=0; i < 8; i++) { UINT32 s1 = (UINT32)(UINT16)VREG_S(VS1REG, i); @@ -1012,6 +1793,8 @@ void rsp_cop2::handle_vector_ops(UINT32 op) m_vres[i] = ACCUM_L(i); } WRITEBACK_RESULT(); +#endif + // break; } @@ -1026,6 +1809,24 @@ void rsp_cop2::handle_vector_ops(UINT32 op) // The result is stored into accumulator // The middle slice of accumulator is stored into destination element + //printf("MUDM "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + rsp_vec_t acc_lo, acc_mid, acc_hi; + + acc_lo = read_acc_lo(acc); + acc_mid = read_acc_mid(acc); + acc_hi = read_acc_hi(acc); + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_vmadm_vmudm(op, vs, vt_shuffle, vec_zero(), &acc_lo, &acc_mid, &acc_hi); + + write_acc_lo(acc, acc_lo); + write_acc_mid(acc, acc_mid); + write_acc_hi(acc, acc_hi); +#else for (i=0; i < 8; i++) { INT32 s1 = (INT32)(INT16)VREG_S(VS1REG, i); @@ -1039,6 +1840,8 @@ void rsp_cop2::handle_vector_ops(UINT32 op) m_vres[i] = ACCUM_M(i); } WRITEBACK_RESULT(); +#endif + // break; } @@ -1054,6 +1857,22 @@ void rsp_cop2::handle_vector_ops(UINT32 op) // The result is stored into accumulator // The low slice of accumulator is stored into destination element + //printf("MUDN "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + rsp_vec_t acc_lo = read_acc_lo(acc); + rsp_vec_t acc_mid = read_acc_mid(acc); + rsp_vec_t acc_hi = read_acc_hi(acc); + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_vmadn_vmudn(op, vs, vt_shuffle, vec_zero(), &acc_lo, &acc_mid, &acc_hi); + + write_acc_lo(acc, acc_lo); + write_acc_mid(acc, acc_mid); + write_acc_hi(acc, acc_hi); +#else for (i=0; i < 8; i++) { INT32 s1 = (UINT16)VREG_S(VS1REG, i); // not sign-extended @@ -1067,6 +1886,8 @@ void rsp_cop2::handle_vector_ops(UINT32 op) m_vres[i] = ACCUM_L(i); } WRITEBACK_RESULT(); +#endif + // break; } @@ -1081,6 +1902,24 @@ void rsp_cop2::handle_vector_ops(UINT32 op) // The result is stored into highest 32 bits of accumulator, the low slice is zero // The highest 32 bits of accumulator is saturated into destination element + //printf("MUDH "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + rsp_vec_t acc_lo, acc_mid, acc_hi; + + acc_lo = read_acc_lo(acc); + acc_mid = read_acc_mid(acc); + acc_hi = read_acc_hi(acc); + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_vmadh_vmudh(op, vs, vt_shuffle, vec_zero(), &acc_lo, &acc_mid, &acc_hi); + + write_acc_lo(acc, acc_lo); + write_acc_mid(acc, acc_mid); + write_acc_hi(acc, acc_hi); +#else for (i=0; i < 8; i++) { INT32 s1 = (INT32)(INT16)VREG_S(VS1REG, i); @@ -1096,6 +1935,8 @@ void rsp_cop2::handle_vector_ops(UINT32 op) m_vres[i] = (INT16)(r); } WRITEBACK_RESULT(); +#endif + // break; } @@ -1109,6 +1950,24 @@ void rsp_cop2::handle_vector_ops(UINT32 op) // Multiplies signed integer by signed integer * 2 // The result is added to accumulator + //printf("MACF "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + rsp_vec_t acc_lo, acc_mid, acc_hi; + + acc_lo = read_acc_lo(acc); + acc_mid = read_acc_mid(acc); + acc_hi = read_acc_hi(acc); + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_vmacf_vmacu(op, vs, vt_shuffle, vec_zero(), &acc_lo, &acc_mid, &acc_hi); + + write_acc_lo(acc, acc_lo); + write_acc_mid(acc, acc_mid); + write_acc_hi(acc, acc_hi); +#else for (i=0; i < 8; i++) { INT32 s1 = (INT32)(INT16)VREG_S(VS1REG, i); @@ -1130,6 +1989,8 @@ void rsp_cop2::handle_vector_ops(UINT32 op) m_vres[i] = SATURATE_ACCUM(i, 1, 0x8000, 0x7fff); } WRITEBACK_RESULT(); +#endif + // break; } case 0x09: /* VMACU */ @@ -1140,6 +2001,24 @@ void rsp_cop2::handle_vector_ops(UINT32 op) // ------------------------------------------------------ // + //printf("MACU "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + rsp_vec_t acc_lo, acc_mid, acc_hi; + + acc_lo = read_acc_lo(acc); + acc_mid = read_acc_mid(acc); + acc_hi = read_acc_hi(acc); + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_vmacf_vmacu(op, vs, vt_shuffle, vec_zero(), &acc_lo, &acc_mid, &acc_hi); + + write_acc_lo(acc, acc_lo); + write_acc_mid(acc, acc_mid); + write_acc_hi(acc, acc_hi); +#else for (i = 0; i < 8; i++) { INT32 s1 = (INT32)(INT16)VREG_S(VS1REG, i); @@ -1176,6 +2055,8 @@ void rsp_cop2::handle_vector_ops(UINT32 op) } } WRITEBACK_RESULT(); +#endif + // break; } @@ -1190,6 +2071,24 @@ void rsp_cop2::handle_vector_ops(UINT32 op) // Adds the higher 16 bits of the 32-bit result to accumulator // The low slice of accumulator is stored into destination element + //printf("MADL "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + rsp_vec_t acc_lo, acc_mid, acc_hi; + + acc_lo = read_acc_lo(acc); + acc_mid = read_acc_mid(acc); + acc_hi = read_acc_hi(acc); + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_vmadl_vmudl(op, vs, vt_shuffle, vec_zero(), &acc_lo, &acc_mid, &acc_hi); + + write_acc_lo(acc, acc_lo); + write_acc_mid(acc, acc_mid); + write_acc_hi(acc, acc_hi); +#else for (i = 0; i < 8; i++) { UINT32 s1 = (UINT32)(UINT16)VREG_S(VS1REG, i); @@ -1205,6 +2104,8 @@ void rsp_cop2::handle_vector_ops(UINT32 op) m_vres[i] = SATURATE_ACCUM(i, 0, 0x0000, 0xffff); } WRITEBACK_RESULT(); +#endif + // break; } @@ -1219,6 +2120,24 @@ void rsp_cop2::handle_vector_ops(UINT32 op) // The result is added into accumulator // The middle slice of accumulator is stored into destination element + //printf("MADM "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + rsp_vec_t acc_lo, acc_mid, acc_hi; + + acc_lo = read_acc_lo(acc); + acc_mid = read_acc_mid(acc); + acc_hi = read_acc_hi(acc); + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_vmadm_vmudm(op, vs, vt_shuffle, vec_zero(), &acc_lo, &acc_mid, &acc_hi); + + write_acc_lo(acc, acc_lo); + write_acc_mid(acc, acc_mid); + write_acc_hi(acc, acc_hi); +#else for (i=0; i < 8; i++) { UINT32 s1 = (INT32)(INT16)VREG_S(VS1REG, i); @@ -1236,6 +2155,8 @@ void rsp_cop2::handle_vector_ops(UINT32 op) m_vres[i] = SATURATE_ACCUM(i, 1, 0x8000, 0x7fff); } WRITEBACK_RESULT(); +#endif + // break; } @@ -1250,6 +2171,24 @@ void rsp_cop2::handle_vector_ops(UINT32 op) // The result is added into accumulator // The low slice of accumulator is stored into destination element + //printf("MADN "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + rsp_vec_t acc_lo, acc_mid, acc_hi; + + acc_lo = read_acc_lo(acc); + acc_mid = read_acc_mid(acc); + acc_hi = read_acc_hi(acc); + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_vmadn_vmudn(op, vs, vt_shuffle, vec_zero(), &acc_lo, &acc_mid, &acc_hi); + + write_acc_lo(acc, acc_lo); + write_acc_mid(acc, acc_mid); + write_acc_hi(acc, acc_hi); +#else for (i=0; i < 8; i++) { INT32 s1 = (UINT16)VREG_S(VS1REG, i); // not sign-extended @@ -1270,6 +2209,8 @@ void rsp_cop2::handle_vector_ops(UINT32 op) } WRITEBACK_RESULT(); +#endif + // break; } @@ -1284,6 +2225,24 @@ void rsp_cop2::handle_vector_ops(UINT32 op) // The result is added into highest 32 bits of accumulator, the low slice is zero // The highest 32 bits of accumulator is saturated into destination element + //printf("MADH "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + rsp_vec_t acc_lo, acc_mid, acc_hi; + + acc_lo = read_acc_lo(acc); + acc_mid = read_acc_mid(acc); + acc_hi = read_acc_hi(acc); + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_vmadh_vmudh(op, vs, vt_shuffle, vec_zero(), &acc_lo, &acc_mid, &acc_hi); + + write_acc_lo(acc, acc_lo); + write_acc_mid(acc, acc_mid); + write_acc_hi(acc, acc_hi); +#else for (i = 0; i < 8; i++) { INT32 s1 = (INT32)(INT16)VREG_S(VS1REG, i); @@ -1300,6 +2259,8 @@ void rsp_cop2::handle_vector_ops(UINT32 op) } WRITEBACK_RESULT(); +#endif + // break; } @@ -1314,6 +2275,21 @@ void rsp_cop2::handle_vector_ops(UINT32 op) // TODO: check VS2REG == VDREG + //printf("ADD "); +#if USE_SIMD + rsp_vec_t acc_lo; + UINT16 *acc = m_acc.s; + rsp_vec_t carry = read_vco_lo(m_flags[RSP_VCO].s); + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_vadd(vs, vt_shuffle, carry, &acc_lo); + + write_vco_hi(m_flags[RSP_VCO].s, vec_zero()); + write_vco_lo(m_flags[RSP_VCO].s, vec_zero()); + write_acc_lo(acc, acc_lo); +#else for (i=0; i < 8; i++) { INT32 s1 = (INT32)(INT16)VREG_S(VS1REG, i); @@ -1329,6 +2305,8 @@ void rsp_cop2::handle_vector_ops(UINT32 op) CLEAR_ZERO_FLAGS(); CLEAR_CARRY_FLAGS(); WRITEBACK_RESULT(); +#endif + // break; } @@ -1343,6 +2321,21 @@ void rsp_cop2::handle_vector_ops(UINT32 op) // TODO: check VS2REG == VDREG + //printf("SUB "); +#if USE_SIMD + rsp_vec_t acc_lo; + UINT16 *acc = m_acc.s; + rsp_vec_t carry = read_vco_lo(m_flags[RSP_VCO].s); + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_vsub(vs, vt_shuffle, carry, &acc_lo); + + write_vco_hi(m_flags[RSP_VCO].s, vec_zero()); + write_vco_lo(m_flags[RSP_VCO].s, vec_zero()); + write_acc_lo(acc, acc_lo); +#else for (i = 0; i < 8; i++) { INT32 s1 = (INT32)(INT16)VREG_S(VS1REG, i); @@ -1359,6 +2352,8 @@ void rsp_cop2::handle_vector_ops(UINT32 op) CLEAR_ZERO_FLAGS(); CLEAR_CARRY_FLAGS(); WRITEBACK_RESULT(); +#endif + // break; } @@ -1372,6 +2367,18 @@ void rsp_cop2::handle_vector_ops(UINT32 op) // Changes the sign of source register 2 if source register 1 is negative and stores // the result to destination register + //printf("ABS "); +#if USE_SIMD + rsp_vec_t acc_lo; + UINT16 *acc = m_acc.s; + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_vabs(vs, vt_shuffle, vec_zero(), &acc_lo); + + write_acc_lo(acc, acc_lo); +#else for (i=0; i < 8; i++) { INT16 s1 = (INT16)VREG_S(VS1REG, i); @@ -1400,6 +2407,8 @@ void rsp_cop2::handle_vector_ops(UINT32 op) SET_ACCUM_L(m_vres[i], i); } WRITEBACK_RESULT(); +#endif + // break; } @@ -1414,6 +2423,20 @@ void rsp_cop2::handle_vector_ops(UINT32 op) // TODO: check VS2REG = VDREG + //printf("ADDC "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + rsp_vec_t sn; + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_vaddc(vs, vt_shuffle, vec_zero(), &sn); + + write_vco_hi(m_flags[RSP_VCO].s, vec_zero()); + write_vco_lo(m_flags[RSP_VCO].s, sn); + write_acc_lo(acc, m_v[VDREG].v); +#else CLEAR_ZERO_FLAGS(); CLEAR_CARRY_FLAGS(); @@ -1432,6 +2455,8 @@ void rsp_cop2::handle_vector_ops(UINT32 op) } } WRITEBACK_RESULT(); +#endif + // break; } @@ -1446,6 +2471,20 @@ void rsp_cop2::handle_vector_ops(UINT32 op) // TODO: check VS2REG = VDREG + //printf("SUBC "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + rsp_vec_t eq, sn; + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_vsubc(vs, vt_shuffle, vec_zero(), &eq, &sn); + + write_vco_hi(m_flags[RSP_VCO].s, eq); + write_vco_lo(m_flags[RSP_VCO].s, sn); + write_acc_lo(acc, m_v[VDREG].v); +#else CLEAR_ZERO_FLAGS(); CLEAR_CARRY_FLAGS(); @@ -1468,6 +2507,8 @@ void rsp_cop2::handle_vector_ops(UINT32 op) } } WRITEBACK_RESULT(); +#endif + // break; } @@ -1480,6 +2521,26 @@ void rsp_cop2::handle_vector_ops(UINT32 op) // // Stores high, middle or low slice of accumulator to destination vector + //printf("SAW "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + switch (EL) + { + case 8: + m_v[VDREG].v = read_acc_hi(acc); + break; + case 9: + m_v[VDREG].v = read_acc_mid(acc); + break; + case 10: + m_v[VDREG].v = read_acc_lo(acc); + break; + + default: + m_v[VDREG].v = _mm_setzero_si128(); + break; + } +#else switch (EL) { case 0x08: // VSAWH @@ -1510,6 +2571,8 @@ void rsp_cop2::handle_vector_ops(UINT32 op) printf("RSP: VSAW: el = %d\n", EL);//??? ??? exit(0); } +#endif + // break; } @@ -1523,6 +2586,25 @@ void rsp_cop2::handle_vector_ops(UINT32 op) // Sets compare flags if elements in VS1 are less than VS2 // Moves the element in VS2 to destination vector + //printf("LT "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + rsp_vec_t le; + + rsp_vec_t eq = read_vco_hi(m_flags[RSP_VCO].s); + rsp_vec_t sign = read_vco_lo(m_flags[RSP_VCO].s); + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_veq_vge_vlt_vne(op, vs, vt_shuffle, vec_zero(), &le, eq, sign); + + write_vcc_hi(m_flags[RSP_VCC].s, vec_zero()); + write_vcc_lo(m_flags[RSP_VCC].s, le); + write_vco_hi(m_flags[RSP_VCO].s, vec_zero()); + write_vco_lo(m_flags[RSP_VCO].s, vec_zero()); + write_acc_lo(acc, m_v[VDREG].v); +#else CLEAR_COMPARE_FLAGS(); CLEAR_CLIP2_FLAGS(); @@ -1558,6 +2640,8 @@ void rsp_cop2::handle_vector_ops(UINT32 op) CLEAR_CARRY_FLAGS(); CLEAR_ZERO_FLAGS(); WRITEBACK_RESULT(); +#endif + // break; } @@ -1571,6 +2655,25 @@ void rsp_cop2::handle_vector_ops(UINT32 op) // Sets compare flags if elements in VS1 are equal with VS2 // Moves the element in VS2 to destination vector + //printf("EQ "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + rsp_vec_t le; + + rsp_vec_t eq = read_vco_hi(m_flags[RSP_VCO].s); + rsp_vec_t sign = read_vco_lo(m_flags[RSP_VCO].s); + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_veq_vge_vlt_vne(op, vs, vt_shuffle, vec_zero(), &le, eq, sign); + + write_vcc_hi(m_flags[RSP_VCC].s, vec_zero()); + write_vcc_lo(m_flags[RSP_VCC].s, le); + write_vco_hi(m_flags[RSP_VCO].s, vec_zero()); + write_vco_lo(m_flags[RSP_VCO].s, vec_zero()); + write_acc_lo(acc, m_v[VDREG].v); +#else CLEAR_COMPARE_FLAGS(); CLEAR_CLIP2_FLAGS(); @@ -1594,6 +2697,8 @@ void rsp_cop2::handle_vector_ops(UINT32 op) CLEAR_ZERO_FLAGS(); CLEAR_CARRY_FLAGS(); WRITEBACK_RESULT(); +#endif + // break; } @@ -1607,6 +2712,25 @@ void rsp_cop2::handle_vector_ops(UINT32 op) // Sets compare flags if elements in VS1 are not equal with VS2 // Moves the element in VS2 to destination vector + //printf("NE "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + rsp_vec_t le; + + rsp_vec_t eq = read_vco_hi(m_flags[RSP_VCO].s); + rsp_vec_t sign = read_vco_lo(m_flags[RSP_VCO].s); + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_veq_vge_vlt_vne(op, vs, vt_shuffle, vec_zero(), &le, eq, sign); + + write_vcc_hi(m_flags[RSP_VCC].s, vec_zero()); + write_vcc_lo(m_flags[RSP_VCC].s, le); + write_vco_hi(m_flags[RSP_VCO].s, vec_zero()); + write_vco_lo(m_flags[RSP_VCO].s, vec_zero()); + write_acc_lo(acc, m_v[VDREG].v); +#else CLEAR_COMPARE_FLAGS(); CLEAR_CLIP2_FLAGS(); @@ -1631,6 +2755,8 @@ void rsp_cop2::handle_vector_ops(UINT32 op) CLEAR_CARRY_FLAGS(); CLEAR_ZERO_FLAGS(); WRITEBACK_RESULT(); +#endif + // break; } @@ -1644,6 +2770,25 @@ void rsp_cop2::handle_vector_ops(UINT32 op) // Sets compare flags if elements in VS1 are greater or equal with VS2 // Moves the element in VS2 to destination vector + //printf("GE "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + rsp_vec_t le; + + rsp_vec_t eq = read_vco_hi(m_flags[RSP_VCO].s); + rsp_vec_t sign = read_vco_lo(m_flags[RSP_VCO].s); + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_veq_vge_vlt_vne(op, vs, vt_shuffle, vec_zero(), &le, eq, sign); + + write_vcc_hi(m_flags[RSP_VCC].s, vec_zero()); + write_vcc_lo(m_flags[RSP_VCC].s, le); + write_vco_hi(m_flags[RSP_VCO].s, vec_zero()); + write_vco_lo(m_flags[RSP_VCO].s, vec_zero()); + write_acc_lo(acc, m_v[VDREG].v); +#else CLEAR_COMPARE_FLAGS(); CLEAR_CLIP2_FLAGS(); @@ -1668,6 +2813,8 @@ void rsp_cop2::handle_vector_ops(UINT32 op) CLEAR_CARRY_FLAGS(); CLEAR_ZERO_FLAGS(); WRITEBACK_RESULT(); +#endif + // break; } @@ -1680,16 +2827,37 @@ void rsp_cop2::handle_vector_ops(UINT32 op) // // Vector clip low + //printf("CL "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + + rsp_vec_t ge = read_vcc_hi(m_flags[RSP_VCC].s); + rsp_vec_t le = read_vcc_lo(m_flags[RSP_VCC].s); + rsp_vec_t eq = read_vco_hi(m_flags[RSP_VCO].s); + rsp_vec_t sign = read_vco_lo(m_flags[RSP_VCO].s); + rsp_vec_t vce = read_vce(m_flags[RSP_VCE].s); + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + m_v[VDREG].v = vec_vcl(vs, vt_shuffle, vec_zero(), &ge, &le, eq, sign, vce); + + write_vcc_hi(m_flags[RSP_VCC].s, ge); + write_vcc_lo(m_flags[RSP_VCC].s, le); + write_vco_hi(m_flags[RSP_VCO].s, vec_zero()); + write_vco_lo(m_flags[RSP_VCO].s, vec_zero()); + write_vce(m_flags[RSP_VCE].s, vec_zero()); + write_acc_lo(acc, m_v[VDREG].v); +#else for (i = 0; i < 8; i++) { INT16 s1 = VREG_S(VS1REG, i); INT16 s2 = VREG_S(VS2REG, VEC_EL_2(EL, i)); - if (CARRY_FLAG(i) != 0) + if (CARRY_FLAG(i) != 0) // vco_lo { - if (ZERO_FLAG(i) != 0) + if (ZERO_FLAG(i) != 0) // vco_hi { - if (COMPARE_FLAG(i) != 0) + if (COMPARE_FLAG(i) != 0) // vcc_lo { SET_ACCUM_L(-(UINT16)s2, i); } @@ -1700,7 +2868,7 @@ void rsp_cop2::handle_vector_ops(UINT32 op) } else { - if (CLIP1_FLAG(i) != 0) + if (CLIP1_FLAG(i) != 0) // vce { if (((UINT32)(UINT16)(s1) + (UINT32)(UINT16)(s2)) > 0x10000) { @@ -1730,9 +2898,9 @@ void rsp_cop2::handle_vector_ops(UINT32 op) } else { - if (ZERO_FLAG(i) != 0) + if (ZERO_FLAG(i) != 0) // vco_hi { - if (CLIP2_FLAG(i) != 0) + if (CLIP2_FLAG(i) != 0) // vcc_hi { SET_ACCUM_L(s2, i); } @@ -1758,10 +2926,12 @@ void rsp_cop2::handle_vector_ops(UINT32 op) m_vres[i] = ACCUM_L(i); } - CLEAR_CARRY_FLAGS(); - CLEAR_ZERO_FLAGS(); - CLEAR_CLIP1_FLAGS(); + CLEAR_CARRY_FLAGS(); // vco_lo + CLEAR_ZERO_FLAGS(); // vco_hi + CLEAR_CLIP1_FLAGS(); // vce WRITEBACK_RESULT(); +#endif + // break; } @@ -1774,6 +2944,23 @@ void rsp_cop2::handle_vector_ops(UINT32 op) // // Vector clip high + //printf("CH "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + rsp_vec_t ge, le, sign, eq, vce; + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_vch(vs, vt_shuffle, vec_zero(), &ge, &le, &eq, &sign, &vce); + + write_vcc_hi(m_flags[RSP_VCC].s, ge); + write_vcc_lo(m_flags[RSP_VCC].s, le); + write_vco_hi(m_flags[RSP_VCO].s, eq); + write_vco_lo(m_flags[RSP_VCO].s, sign); + write_vce(m_flags[RSP_VCE].s, vce); + write_acc_lo(acc, m_v[VDREG].v); +#else CLEAR_CARRY_FLAGS(); CLEAR_COMPARE_FLAGS(); CLEAR_CLIP1_FLAGS(); @@ -1846,6 +3033,8 @@ void rsp_cop2::handle_vector_ops(UINT32 op) SET_ACCUM_L(m_vres[i], i); } WRITEBACK_RESULT(); +#endif + // break; } @@ -1858,6 +3047,23 @@ void rsp_cop2::handle_vector_ops(UINT32 op) // // Vector clip reverse + //printf("CR "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + rsp_vec_t ge, le; + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_vcr(vs, vt_shuffle, vec_zero(), &ge, &le); + + write_vcc_hi(m_flags[RSP_VCC].s, ge); + write_vcc_lo(m_flags[RSP_VCC].s, le); + write_vco_hi(m_flags[RSP_VCO].s, vec_zero()); + write_vco_lo(m_flags[RSP_VCO].s, vec_zero()); + write_vce(m_flags[RSP_VCE].s, vec_zero()); + write_acc_lo(acc, m_v[VDREG].v); +#else CLEAR_CARRY_FLAGS(); CLEAR_COMPARE_FLAGS(); CLEAR_CLIP1_FLAGS(); @@ -1905,6 +3111,8 @@ void rsp_cop2::handle_vector_ops(UINT32 op) m_vres[i] = ACCUM_L(i); } WRITEBACK_RESULT(); +#endif + // break; } @@ -1917,6 +3125,20 @@ void rsp_cop2::handle_vector_ops(UINT32 op) // // Merges two vectors according to compare flags + //printf("MRG "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + rsp_vec_t le = read_vcc_lo(m_flags[RSP_VCC].s); + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_vmrg(vs, vt_shuffle, le); + + write_vco_hi(m_flags[RSP_VCO].s, vec_zero()); + write_vco_lo(m_flags[RSP_VCO].s, vec_zero()); + write_acc_lo(acc, m_v[VDREG].v); +#else for (i = 0; i < 8; i++) { if (COMPARE_FLAG(i) != 0) @@ -1931,6 +3153,8 @@ void rsp_cop2::handle_vector_ops(UINT32 op) SET_ACCUM_L(m_vres[i], i); } WRITEBACK_RESULT(); +#endif + // break; } case 0x28: /* VAND */ @@ -1942,12 +3166,25 @@ void rsp_cop2::handle_vector_ops(UINT32 op) // // Bitwise AND of two vector registers + //printf("AND "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_vand_vnand(op, vs, vt_shuffle); + + write_acc_lo(acc, m_v[VDREG].v); +#else for (i = 0; i < 8; i++) { m_vres[i] = VREG_S(VS1REG, i) & VREG_S(VS2REG, VEC_EL_2(EL, i)); SET_ACCUM_L(m_vres[i], i); } WRITEBACK_RESULT(); +#endif + // break; } case 0x29: /* VNAND */ @@ -1959,12 +3196,25 @@ void rsp_cop2::handle_vector_ops(UINT32 op) // // Bitwise NOT AND of two vector registers + //printf("NAND "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_vand_vnand(op, vs, vt_shuffle); + + write_acc_lo(acc, m_v[VDREG].v); +#else for (i = 0; i < 8; i++) { m_vres[i] = ~((VREG_S(VS1REG, i) & VREG_S(VS2REG, VEC_EL_2(EL, i)))); SET_ACCUM_L(m_vres[i], i); } WRITEBACK_RESULT(); +#endif + // break; } case 0x2a: /* VOR */ @@ -1976,12 +3226,25 @@ void rsp_cop2::handle_vector_ops(UINT32 op) // // Bitwise OR of two vector registers + //printf("OR "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_vor_vnor(op, vs, vt_shuffle); + + write_acc_lo(acc, m_v[VDREG].v); +#else for (i = 0; i < 8; i++) { m_vres[i] = VREG_S(VS1REG, i) | VREG_S(VS2REG, VEC_EL_2(EL, i)); SET_ACCUM_L(m_vres[i], i); } WRITEBACK_RESULT(); +#endif + // break; } case 0x2b: /* VNOR */ @@ -1993,12 +3256,25 @@ void rsp_cop2::handle_vector_ops(UINT32 op) // // Bitwise NOT OR of two vector registers + //printf("NOR "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_vor_vnor(op, vs, vt_shuffle); + + write_acc_lo(acc, m_v[VDREG].v); +#else for (i=0; i < 8; i++) { m_vres[i] = ~((VREG_S(VS1REG, i) | VREG_S(VS2REG, VEC_EL_2(EL, i)))); SET_ACCUM_L(m_vres[i], i); } WRITEBACK_RESULT(); +#endif + // break; } case 0x2c: /* VXOR */ @@ -2010,12 +3286,25 @@ void rsp_cop2::handle_vector_ops(UINT32 op) // // Bitwise XOR of two vector registers + //printf("XOR "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_vxor_vnxor(op, vs, vt_shuffle); + + write_acc_lo(acc, m_v[VDREG].v); +#else for (i=0; i < 8; i++) { m_vres[i] = VREG_S(VS1REG, i) ^ VREG_S(VS2REG, VEC_EL_2(EL, i)); SET_ACCUM_L(m_vres[i], i); } WRITEBACK_RESULT(); +#endif + // break; } case 0x2d: /* VNXOR */ @@ -2027,12 +3316,25 @@ void rsp_cop2::handle_vector_ops(UINT32 op) // // Bitwise NOT XOR of two vector registers + //printf("NXOR "); +#if USE_SIMD + UINT16 *acc = m_acc.s; + + rsp_vec_t vs = vec_load_unshuffled_operand(m_v[VS1REG].s); + rsp_vec_t vt_shuffle = vec_load_and_shuffle_operand(m_v[VS2REG].s, EL); + + m_v[VDREG].v = vec_vxor_vnxor(op, vs, vt_shuffle); + + write_acc_lo(acc, m_v[VDREG].v); +#else for (i=0; i < 8; i++) { m_vres[i] = ~((VREG_S(VS1REG, i) ^ VREG_S(VS2REG, VEC_EL_2(EL, i)))); SET_ACCUM_L(m_vres[i], i); } WRITEBACK_RESULT(); +#endif + // break; } @@ -2044,6 +3346,16 @@ void rsp_cop2::handle_vector_ops(UINT32 op) // ------------------------------------------------------ // // Calculates reciprocal + + //printf("RCP "); +#if USE_SIMD + write_acc_lo(m_acc.s, vec_load_and_shuffle_operand(m_v[VS2REG].s, EL)); + + INT32 dp = op & m_dp_flag; + m_dp_flag = 0; + + m_v[VDREG].v = vec_vrcp_vrsq(op, dp, VS2REG, EL, VDREG, VS1REG); +#else INT32 shifter = 0; INT32 rec = (INT16)(VREG_S(VS2REG, EL & 7)); @@ -2092,6 +3404,8 @@ void rsp_cop2::handle_vector_ops(UINT32 op) } +#endif + // break; } @@ -2104,6 +3418,15 @@ void rsp_cop2::handle_vector_ops(UINT32 op) // // Calculates reciprocal low part + //printf("RCPL "); +#if USE_SIMD + write_acc_lo(m_acc.s, vec_load_and_shuffle_operand(m_v[VS2REG].s, EL)); + + INT32 dp = op & m_dp_flag; + m_dp_flag = 0; + + m_v[VDREG].v = vec_vrcp_vrsq(op, dp, VS2REG, EL, VDREG, VS1REG); +#else INT32 shifter = 0; INT32 rec = (INT16)VREG_S(VS2REG, EL & 7); @@ -2168,6 +3491,8 @@ void rsp_cop2::handle_vector_ops(UINT32 op) SET_ACCUM_L(VREG_S(VS2REG, VEC_EL_2(EL, i)), i); } +#endif + // break; } @@ -2180,6 +3505,14 @@ void rsp_cop2::handle_vector_ops(UINT32 op) // // Calculates reciprocal high part + //printf("RCPH "); +#if USE_SIMD + write_acc_lo(m_acc.s, vec_load_and_shuffle_operand(m_v[VS2REG].s, EL)); + + m_dp_flag = 1; + + m_v[VDREG].v = vec_vdivh(VS2REG, EL, VDREG, VS1REG); +#else m_reciprocal_high = (VREG_S(VS2REG, EL & 7)) << 16; m_dp_allowed = 1; @@ -2190,6 +3523,8 @@ void rsp_cop2::handle_vector_ops(UINT32 op) VREG_S(VDREG, VS1REG & 7) = (INT16)(m_reciprocal_res >> 16); +#endif + // break; } @@ -2202,11 +3537,18 @@ void rsp_cop2::handle_vector_ops(UINT32 op) // // Moves element from vector to destination vector + //printf("MOV "); +#if USE_SIMD + write_acc_lo(m_acc.s, vec_load_and_shuffle_operand(m_v[VS2REG].s, EL)); + m_v[VDREG].v = vec_vmov(VS2REG, EL, VDREG, VS1REG); +#else VREG_S(VDREG, VS1REG & 7) = VREG_S(VS2REG, EL & 7); for (i = 0; i < 8; i++) { SET_ACCUM_L(VREG_S(VS2REG, VEC_EL_2(EL, i)), i); } +#endif + // break; } @@ -2219,6 +3561,15 @@ void rsp_cop2::handle_vector_ops(UINT32 op) // // Calculates reciprocal square-root + //printf("RSQ "); +#if USE_SIMD + write_acc_lo(m_acc.s, vec_load_and_shuffle_operand(m_v[VS2REG].s, EL)); + + INT32 dp = op & m_dp_flag; + m_dp_flag = 0; + + m_v[VDREG].v = vec_vrcp_vrsq(op, dp, VS2REG, EL, VDREG, VS1REG); +#else INT32 shifter = 0; INT32 rec = (INT16)(VREG_S(VS2REG, EL & 7)); @@ -2268,6 +3619,8 @@ void rsp_cop2::handle_vector_ops(UINT32 op) SET_ACCUM_L(VREG_S(VS2REG, VEC_EL_2(EL, i)), i); } +#endif + // break; } @@ -2280,6 +3633,15 @@ void rsp_cop2::handle_vector_ops(UINT32 op) // // Calculates reciprocal square-root low part + //printf("RSQL "); +#if USE_SIMD + write_acc_lo(m_acc.s, vec_load_and_shuffle_operand(m_v[VS2REG].s, EL)); + + INT32 dp = op & m_dp_flag; + m_dp_flag = 0; + + m_v[VDREG].v = vec_vrcp_vrsq(op, dp, VS2REG, EL, VDREG, VS1REG); +#else INT32 shifter = 0; INT32 rec = (INT16)VREG_S(VS2REG, EL & 7); INT32 datainput = rec; @@ -2347,6 +3709,8 @@ void rsp_cop2::handle_vector_ops(UINT32 op) SET_ACCUM_L(VREG_S(VS2REG, VEC_EL_2(EL, i)), i); } +#endif + // break; } @@ -2359,6 +3723,14 @@ void rsp_cop2::handle_vector_ops(UINT32 op) // // Calculates reciprocal square-root high part + //printf("RSQH "); +#if USE_SIMD + write_acc_lo(m_acc.s, vec_load_and_shuffle_operand(m_v[VS2REG].s, EL)); + + m_dp_flag = 1; + + m_v[VDREG].v = vec_vdivh(VS2REG, EL, VDREG, VS1REG); +#else m_reciprocal_high = (VREG_S(VS2REG, EL & 7)) << 16; m_dp_allowed = 1; @@ -2368,6 +3740,8 @@ void rsp_cop2::handle_vector_ops(UINT32 op) } VREG_S(VDREG, VS1REG & 7) = (INT16)(m_reciprocal_res >> 16); // store high part +#endif + // break; } @@ -2380,6 +3754,7 @@ void rsp_cop2::handle_vector_ops(UINT32 op) // // Vector null instruction + //printf("NOP "); break; } @@ -2402,6 +3777,7 @@ void rsp_cop2::handle_cop2(UINT32 op) // | 010010 | 00000 | TTTTT | DDDDD | IIII | 0000000 | // --------------------------------------------------- // + //printf("MFC2 "); int el = (op >> 7) & 0xf; UINT16 b1 = VREG_B(RDREG, (el+0) & 0xf); UINT16 b2 = VREG_B(RDREG, (el+1) & 0xf); @@ -2416,8 +3792,16 @@ void rsp_cop2::handle_cop2(UINT32 op) // | 010010 | 00010 | TTTTT | DDDDD | 00000000000 | // ------------------------------------------------ // + //printf("CFC2 "); if (RTREG) { +#if USE_SIMD + INT32 src = RDREG & 3; + if (src == 3) { + src = 2; + } + RTVAL = get_flags(m_flags[src].s); +#else switch(RDREG) { case 0: @@ -2469,6 +3853,7 @@ void rsp_cop2::handle_cop2(UINT32 op) ((CLIP1_FLAG(6) & 1) << 6) | ((CLIP1_FLAG(7) & 1) << 7); } +#endif } break; } @@ -2480,6 +3865,7 @@ void rsp_cop2::handle_cop2(UINT32 op) // | 010010 | 00100 | TTTTT | DDDDD | IIII | 0000000 | // --------------------------------------------------- // + //printf("MTC2 "); int el = (op >> 7) & 0xf; W_VREG_B(RDREG, (el+0) & 0xf, (RTVAL >> 8) & 0xff); W_VREG_B(RDREG, (el+1) & 0xf, (RTVAL >> 0) & 0xff); @@ -2495,6 +3881,30 @@ void rsp_cop2::handle_cop2(UINT32 op) // switch(RDREG) { +#if USE_SIMD + case 0: + case 1: + case 2: + UINT16 r0 = (RTVAL & (1 << 0)) ? 0xffff : 0; + UINT16 r1 = (RTVAL & (1 << 1)) ? 0xffff : 0; + UINT16 r2 = (RTVAL & (1 << 2)) ? 0xffff : 0; + UINT16 r3 = (RTVAL & (1 << 3)) ? 0xffff : 0; + UINT16 r4 = (RTVAL & (1 << 4)) ? 0xffff : 0; + UINT16 r5 = (RTVAL & (1 << 5)) ? 0xffff : 0; + UINT16 r6 = (RTVAL & (1 << 6)) ? 0xffff : 0; + UINT16 r7 = (RTVAL & (1 << 7)) ? 0xffff : 0; + m_flags[RDREG].__align[0] = _mm_set_epi16(r7, r6, r5, r4, r3, r2, r1, r0); + r0 = (RTVAL & (1 << 8)) ? 0xffff : 0; + r1 = (RTVAL & (1 << 9)) ? 0xffff : 0; + r2 = (RTVAL & (1 << 10)) ? 0xffff : 0; + r3 = (RTVAL & (1 << 11)) ? 0xffff : 0; + r4 = (RTVAL & (1 << 12)) ? 0xffff : 0; + r5 = (RTVAL & (1 << 13)) ? 0xffff : 0; + r6 = (RTVAL & (1 << 14)) ? 0xffff : 0; + r7 = (RTVAL & (1 << 15)) ? 0xffff : 0; + m_flags[RDREG].__align[1] = _mm_set_epi16(r7, r6, r5, r4, r3, r2, r1, r0); + break; +#else case 0: CLEAR_CARRY_FLAGS(); CLEAR_ZERO_FLAGS(); @@ -2548,6 +3958,7 @@ void rsp_cop2::handle_cop2(UINT32 op) if (RTVAL & (1 << 6)) { SET_CLIP1_FLAG(6); } if (RTVAL & (1 << 7)) { SET_CLIP1_FLAG(7); } break; +#endif } break; } @@ -2555,6 +3966,7 @@ void rsp_cop2::handle_cop2(UINT32 op) case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: { + //printf("V"); handle_vector_ops(op); break; } @@ -2563,11 +3975,12 @@ void rsp_cop2::handle_cop2(UINT32 op) m_rsp.unimplemented_opcode(op); break; } + //dump(op); } inline void rsp_cop2::mfc2() { - UINT32 op = m_op; + UINT32 op = m_rspcop2_state->op; int el = (op >> 7) & 0xf; UINT16 b1 = VREG_B(VS1REG, (el+0) & 0xf); @@ -2577,7 +3990,7 @@ inline void rsp_cop2::mfc2() inline void rsp_cop2::cfc2() { - UINT32 op = m_op; + UINT32 op = m_rspcop2_state->op; if (RTREG) { switch(RDREG) @@ -2636,7 +4049,7 @@ inline void rsp_cop2::cfc2() inline void rsp_cop2::mtc2() { - UINT32 op = m_op; + UINT32 op = m_rspcop2_state->op; int el = (op >> 7) & 0xf; VREG_B(VS1REG, (el+0) & 0xf) = (RTVAL >> 8) & 0xff; VREG_B(VS1REG, (el+1) & 0xf) = (RTVAL >> 0) & 0xff; @@ -2644,7 +4057,7 @@ inline void rsp_cop2::mtc2() inline void rsp_cop2::ctc2() { - UINT32 op = m_op; + UINT32 op = m_rspcop2_state->op; switch(RDREG) { case 0: @@ -2756,3 +4169,54 @@ void rsp_cop2::log_instruction_execution() prev_vecs[i].d[1] = m_v[i].d[1]; } } + +void rsp_cop2::dump(UINT32 op) +{ + printf("%08x ", op); + for (int i = 0; i < 32; i++) + { + printf("%08x ", m_rsp.m_rsp_state->r[i]); + } + printf("\n"); + + for (int i = 0; i < 32; i++) + { + printf("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", VREG_B(i, 0), VREG_B(i, 1), VREG_B(i, 2), VREG_B(i, 3), VREG_B(i, 4), VREG_B(i, 5), VREG_B(i, 6), VREG_B(i, 7), VREG_B(i, 8), VREG_B(i, 9), VREG_B(i, 10), VREG_B(i, 11), VREG_B(i, 12), VREG_B(i, 13), VREG_B(i, 14), VREG_B(i, 15)); + } + +#if USE_SIMD + printf("acc_h: %04x|%04x|%04x|%04x|%04x|%04x|%04x|%04x\n", m_acc.s[0], m_acc.s[1], m_acc.s[2], m_acc.s[3], m_acc.s[4], m_acc.s[5], m_acc.s[6], m_acc.s[7]); + printf("acc_m: %04x|%04x|%04x|%04x|%04x|%04x|%04x|%04x\n", m_acc.s[8], m_acc.s[9], m_acc.s[10], m_acc.s[11], m_acc.s[12], m_acc.s[13], m_acc.s[14], m_acc.s[15]); + printf("acc_l: %04x|%04x|%04x|%04x|%04x|%04x|%04x|%04x\n", m_acc.s[16], m_acc.s[17], m_acc.s[18], m_acc.s[19], m_acc.s[20], m_acc.s[21], m_acc.s[22], m_acc.s[23]); + printf("vcc_hi: %04x|%04x|%04x|%04x|%04x|%04x|%04x|%04x\n", m_flags[RSP_VCC].s[0], m_flags[RSP_VCC].s[1], m_flags[RSP_VCC].s[2], m_flags[RSP_VCC].s[3], m_flags[RSP_VCC].s[4], m_flags[RSP_VCC].s[5], m_flags[RSP_VCC].s[6], m_flags[RSP_VCC].s[7]); + printf("vcc_lo: %04x|%04x|%04x|%04x|%04x|%04x|%04x|%04x\n", m_flags[RSP_VCC].s[8], m_flags[RSP_VCC].s[9], m_flags[RSP_VCC].s[10], m_flags[RSP_VCC].s[11], m_flags[RSP_VCC].s[12], m_flags[RSP_VCC].s[13], m_flags[RSP_VCC].s[14], m_flags[RSP_VCC].s[15]); + printf("vco_hi: %04x|%04x|%04x|%04x|%04x|%04x|%04x|%04x\n", m_flags[RSP_VCO].s[0], m_flags[RSP_VCO].s[1], m_flags[RSP_VCO].s[2], m_flags[RSP_VCO].s[3], m_flags[RSP_VCO].s[4], m_flags[RSP_VCO].s[5], m_flags[RSP_VCO].s[6], m_flags[RSP_VCO].s[7]); + printf("vco_lo: %04x|%04x|%04x|%04x|%04x|%04x|%04x|%04x\n", m_flags[RSP_VCO].s[8], m_flags[RSP_VCO].s[9], m_flags[RSP_VCO].s[10], m_flags[RSP_VCO].s[11], m_flags[RSP_VCO].s[12], m_flags[RSP_VCO].s[13], m_flags[RSP_VCO].s[14], m_flags[RSP_VCO].s[15]); + printf("vce: %04x|%04x|%04x|%04x|%04x|%04x|%04x|%04x\n", m_flags[RSP_VCE].s[0], m_flags[RSP_VCE].s[1], m_flags[RSP_VCE].s[2], m_flags[RSP_VCE].s[3], m_flags[RSP_VCE].s[4], m_flags[RSP_VCE].s[5], m_flags[RSP_VCE].s[6], m_flags[RSP_VCE].s[7]); +#else + printf("acc_h: %04x|%04x|%04x|%04x|%04x|%04x|%04x|%04x\n", ACCUM_H(0), ACCUM_H(1), ACCUM_H(2), ACCUM_H(3), ACCUM_H(4), ACCUM_H(5), ACCUM_H(6), ACCUM_H(7)); + printf("acc_m: %04x|%04x|%04x|%04x|%04x|%04x|%04x|%04x\n", ACCUM_M(0), ACCUM_M(1), ACCUM_M(2), ACCUM_M(3), ACCUM_M(4), ACCUM_M(5), ACCUM_M(6), ACCUM_M(7)); + printf("acc_l: %04x|%04x|%04x|%04x|%04x|%04x|%04x|%04x\n", ACCUM_L(0), ACCUM_L(1), ACCUM_L(2), ACCUM_L(3), ACCUM_L(4), ACCUM_L(5), ACCUM_L(6), ACCUM_L(7)); + printf("vcc_hi: %04x|%04x|%04x|%04x|%04x|%04x|%04x|%04x\n", m_vflag[4][0], m_vflag[4][1], m_vflag[4][2], m_vflag[4][3], m_vflag[4][4], m_vflag[4][5], m_vflag[4][6], m_vflag[4][7]); + printf("vcc_lo: %04x|%04x|%04x|%04x|%04x|%04x|%04x|%04x\n", m_vflag[1][0], m_vflag[1][1], m_vflag[1][2], m_vflag[1][3], m_vflag[1][4], m_vflag[1][5], m_vflag[1][6], m_vflag[1][7]); + printf("vco_hi: %04x|%04x|%04x|%04x|%04x|%04x|%04x|%04x\n", m_vflag[3][0], m_vflag[3][1], m_vflag[3][2], m_vflag[3][3], m_vflag[3][4], m_vflag[3][5], m_vflag[3][6], m_vflag[3][7]); + printf("vco_lo: %04x|%04x|%04x|%04x|%04x|%04x|%04x|%04x\n", m_vflag[0][0], m_vflag[0][1], m_vflag[0][2], m_vflag[0][3], m_vflag[0][4], m_vflag[0][5], m_vflag[0][6], m_vflag[0][7]); + printf("vce: %04x|%04x|%04x|%04x|%04x|%04x|%04x|%04x\n", m_vflag[2][0], m_vflag[2][1], m_vflag[2][2], m_vflag[2][3], m_vflag[2][4], m_vflag[2][5], m_vflag[2][6], m_vflag[2][7]); +#endif +} + +void rsp_cop2::dump_dmem() +{ + UINT8* dmem = m_rsp.get_dmem(); + printf("\n"); + for (int i = 0; i < 0x1000; i += 32) + { + printf("%04x: ", i); + for (int j = 0; j < 32; j++) + { + printf("%02x ", dmem[i + j]); + } + printf("\n"); + } + printf("\n"); +}
\ No newline at end of file |