summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/cpu/rsp/rspcp2.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/cpu/rsp/rspcp2.c')
-rw-r--r--src/emu/cpu/rsp/rspcp2.c1536
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