summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/rsp/rsp.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/cpu/rsp/rsp.cpp')
-rw-r--r--src/devices/cpu/rsp/rsp.cpp3023
1 files changed, 2630 insertions, 393 deletions
diff --git a/src/devices/cpu/rsp/rsp.cpp b/src/devices/cpu/rsp/rsp.cpp
index 17b1682b8bd..c72e8652d8c 100644
--- a/src/devices/cpu/rsp/rsp.cpp
+++ b/src/devices/cpu/rsp/rsp.cpp
@@ -9,13 +9,8 @@
#include "emu.h"
#include "rsp.h"
-#include "rspfe.h"
-#include "rspcp2.h"
-#include "rspcp2d.h"
-
-#include "debugger.h"
-
#include "rspdefs.h"
+#include "rspdiv.h"
#include "rsp_dasm.h"
@@ -27,59 +22,72 @@ DEFINE_DEVICE_TYPE(RSP, rsp_device, "rsp", "Nintendo & SGI Reality Signal Proces
#define SAVE_DMEM 0
#define RSP_TEST_SYNC 0
-#define PRINT_VECREG(x) osd_printf_debug("V%d: %04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X\n", (x), \
- (uint16_t)VREG_S((x),0), (uint16_t)VREG_S((x),1), \
- (uint16_t)VREG_S((x),2), (uint16_t)VREG_S((x),3), \
- (uint16_t)VREG_S((x),4), (uint16_t)VREG_S((x),5), \
- (uint16_t)VREG_S((x),6), (uint16_t)VREG_S((x),7))
+#define PRINT_VECREG(x) osd_printf_debug("V%d: %04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X\n", x, \
+ m_v[x].w[0], m_v[x].w[1], m_v[x].w[2], m_v[x].w[3], \
+ m_v[x].w[4], m_v[x].w[5], m_v[x].w[6], m_v[x].w[7])
-#define PRINT_ACCUM(x) osd_printf_debug("A%d: %08X|%08X\n", (x), \
- (uint32_t)( ( ACCUM(x) >> 32 ) & 0x00000000ffffffff ), \
- (uint32_t)( ACCUM(x) & 0x00000000ffffffff ))
+#define PRINT_ACCUM(x) osd_printf_debug("A%d: %08X|%08X\n", x, (uint32_t)(m_accum[x].q >> 32), (uint32_t)m_accum[x].q);
#define SIMM16 ((int32_t)(int16_t)(op))
#define UIMM16 ((uint16_t)(op))
#define UIMM26 (op & 0x03ffffff)
-#define RSVAL (m_rsp_state->r[RSREG])
-#define RTVAL (m_rsp_state->r[RTREG])
-#define RDVAL (m_rsp_state->r[RDREG])
-
-#define JUMP_ABS(addr) { m_nextpc = 0x04001000 | (((addr) << 2) & 0xfff); }
-#define JUMP_ABS_L(addr,l) { m_nextpc = 0x04001000 | (((addr) << 2) & 0xfff); m_rsp_state->r[l] = m_rsp_state->pc + 4; }
-#define JUMP_REL(offset) { m_nextpc = 0x04001000 | ((m_rsp_state->pc + ((offset) << 2)) & 0xfff); }
-#define JUMP_REL_L(offset,l) { m_nextpc = 0x04001000 | ((m_rsp_state->pc + ((offset) << 2)) & 0xfff); m_rsp_state->r[l] = m_rsp_state->pc + 4; }
-#define JUMP_PC(addr) { m_nextpc = 0x04001000 | ((addr) & 0xfff); }
-#define JUMP_PC_L(addr,l) { m_nextpc = 0x04001000 | ((addr) & 0xfff); m_rsp_state->r[l] = m_rsp_state->pc + 4; }
-#define LINK(l) { m_rsp_state->r[l] = m_rsp_state->pc + 4; }
-
-#define CARRY_FLAG(x) (m_vflag[CARRY][x & 7] != 0 ? 0xffff : 0)
-#define COMPARE_FLAG(x) (m_vflag[COMPARE][x & 7] != 0 ? 0xffff : 0)
-#define CLIP1_FLAG(x) (m_vflag[CLIP1][x & 7] != 0 ? 0xffff : 0)
-#define ZERO_FLAG(x) (m_vflag[ZERO][x & 7] != 0 ? 0xffff : 0)
-#define CLIP2_FLAG(x) (m_vflag[CLIP2][x & 7] != 0 ? 0xffff : 0)
-
-#define CLEAR_CARRY_FLAGS() { memset(m_vflag[CARRY], 0, 16); }
-#define CLEAR_COMPARE_FLAGS() { memset(m_vflag[COMPARE], 0, 16); }
-#define CLEAR_CLIP1_FLAGS() { memset(m_vflag[CLIP1], 0, 16); }
-#define CLEAR_ZERO_FLAGS() { memset(m_vflag[ZERO], 0, 16); }
-#define CLEAR_CLIP2_FLAGS() { memset(m_vflag[CLIP2], 0, 16); }
-
-#define SET_CARRY_FLAG(x) { m_vflag[CARRY][x & 7] = 0xffff; }
-#define SET_COMPARE_FLAG(x) { m_vflag[COMPARE][x & 7] = 0xffff; }
-#define SET_CLIP1_FLAG(x) { m_vflag[CLIP1][x & 7] = 0xffff; }
-#define SET_ZERO_FLAG(x) { m_vflag[ZERO][x & 7] = 0xffff; }
-#define SET_CLIP2_FLAG(x) { m_vflag[CLIP2][x & 7] = 0xffff; }
-
-#define CLEAR_CARRY_FLAG(x) { m_vflag[CARRY][x & 7] = 0; }
-#define CLEAR_COMPARE_FLAG(x) { m_vflag[COMPARE][x & 7] = 0; }
-#define CLEAR_CLIP1_FLAG(x) { m_vflag[CLIP1][x & 7] = 0; }
-#define CLEAR_ZERO_FLAG(x) { m_vflag[ZERO][x & 7] = 0; }
-#define CLEAR_CLIP2_FLAG(x) { m_vflag[CLIP2][x & 7] = 0; }
-
-#define ROPCODE(pc) m_program->read_dword(pc)
+#define JUMP_ABS(addr) { m_nextpc = (addr) << 2; }
+#define JUMP_ABS_L(addr,l) { m_nextpc = (addr) << 2; m_r[l] = m_pc + 4; }
+#define JUMP_REL(offset) { m_nextpc = m_pc + ((offset) << 2); }
+#define JUMP_REL_L(offset,l) { m_nextpc = m_pc + ((offset) << 2); m_r[l] = m_pc + 4; }
+#define JUMP_PC(addr) { m_nextpc = addr; }
+#define JUMP_PC_L(addr,l) { m_nextpc = addr; m_r[l] = m_pc + 4; }
+
+#define ROPCODE(pc) m_icache.read_dword(pc & 0xfff)
+
+/***************************************************************************
+ Helpful Vector Defines
+***************************************************************************/
+
+#define VDREG ((op >> 6) & 0x1f)
+#define VS1REG ((op >> 11) & 0x1f)
+#define VS2REG ((op >> 16) & 0x1f)
+#define EL ((op >> 21) & 0xf)
+
+#define VREG_B(reg, offset) m_v[(reg)].b[(offset)^1]
+#define W_VREG_B(reg, offset, val) (m_v[(reg)].b[(offset)^1] = val)
+#define VEC_EL_2(x,z) (vector_elements_2[(x)][(z)])
+
+#define CARRY 0
+#define COMPARE 1
+#define CLIP1 2
+#define ZERO 3
+#define CLIP2 4
+
+#define SLICE_H 3
+#define SLICE_M 2
+#define SLICE_L 1
+#define SLICE_LL 0
+
+#define WRITEBACK_RESULT() memcpy(m_v[VDREG].s, vres, sizeof(uint16_t) * 8);
+
+static const int vector_elements_2[16][8] =
+{
+ { 0, 1, 2, 3, 4, 5, 6, 7 }, // none
+ { 0, 1, 2, 3, 4, 5, 6, 7 }, // ???
+ { 0, 0, 2, 2, 4, 4, 6, 6 }, // 0q
+ { 1, 1, 3, 3, 5, 5, 7, 7 }, // 1q
+ { 0, 0, 0, 0, 4, 4, 4, 4 }, // 0h
+ { 1, 1, 1, 1, 5, 5, 5, 5 }, // 1h
+ { 2, 2, 2, 2, 6, 6, 6, 6 }, // 2h
+ { 3, 3, 3, 3, 7, 7, 7, 7 }, // 3h
+ { 0, 0, 0, 0, 0, 0, 0, 0 }, // 0
+ { 1, 1, 1, 1, 1, 1, 1, 1 }, // 1
+ { 2, 2, 2, 2, 2, 2, 2, 2 }, // 2
+ { 3, 3, 3, 3, 3, 3, 3, 3 }, // 3
+ { 4, 4, 4, 4, 4, 4, 4, 4 }, // 4
+ { 5, 5, 5, 5, 5, 5, 5, 5 }, // 5
+ { 6, 6, 6, 6, 6, 6, 6, 6 }, // 6
+ { 7, 7, 7, 7, 7, 7, 7, 7 }, // 7
+};
/***************************************************************************
DEBUGGING
@@ -103,42 +111,20 @@ DEFINE_DEVICE_TYPE(RSP, rsp_device, "rsp", "Nintendo & SGI Reality Signal Proces
rsp_device::rsp_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: cpu_device(mconfig, RSP, tag, owner, clock)
- , m_program_config("program", ENDIANNESS_BIG, 32, 32)
- , m_cache(CACHE_SIZE + sizeof(internal_rsp_state))
- , m_drcuml(nullptr)
-// , m_drcuml(*this, m_cache, 0, 8, 32, 2)
- , m_drcfe(nullptr)
- , m_drcoptions(0)
- , m_cache_dirty(true)
- , m_numcycles(0)
- , m_format(nullptr)
- , m_arg2(0)
- , m_arg3(0)
- , m_entry(nullptr)
- , m_nocode(nullptr)
- , m_out_of_cycles(nullptr)
- , m_read8(nullptr)
- , m_write8(nullptr)
- , m_read16(nullptr)
- , m_write16(nullptr)
- , m_read32(nullptr)
- , m_write32(nullptr)
- , m_rsp_state(nullptr)
+ , m_imem_config("imem", ENDIANNESS_BIG, 32, 12)
+ , m_dmem_config("dmem", ENDIANNESS_BIG, 32, 12)
, m_exec_output(nullptr)
, m_sr(0)
, m_step_count(0)
, m_ppc(0)
- , m_nextpc(0)
- , m_dmem32(nullptr)
- , m_dmem16(nullptr)
- , m_dmem8(nullptr)
- , m_imem32(nullptr)
- , m_imem16(nullptr)
- , m_imem8(nullptr)
+ , m_nextpc(0xffff)
, m_debugger_temp(0)
- , m_dp_reg_r_func(*this)
+ , m_pc_temp(0)
+ , m_ppc_temp(0)
+ , m_nextpc_temp(0xffff)
+ , m_dp_reg_r_func(*this, 0)
, m_dp_reg_w_func(*this)
- , m_sp_reg_r_func(*this)
+ , m_sp_reg_r_func(*this, 0)
, m_sp_reg_w_func(*this)
, m_sp_set_status_func(*this)
{
@@ -151,7 +137,8 @@ rsp_device::~rsp_device()
device_memory_interface::space_config_vector rsp_device::memory_space_config() const
{
return space_config_vector {
- std::make_pair(AS_PROGRAM, &m_program_config)
+ std::make_pair(AS_PROGRAM, &m_imem_config),
+ std::make_pair(AS_DATA, &m_dmem_config)
};
}
@@ -160,133 +147,34 @@ std::unique_ptr<util::disasm_interface> rsp_device::create_disassembler()
return std::make_unique<rsp_disassembler>();
}
-void rsp_device::rsp_add_imem(uint32_t *base)
-{
- m_imem32 = base;
- m_imem16 = (uint16_t*)base;
- m_imem8 = (uint8_t*)base;
-}
-
-void rsp_device::rsp_add_dmem(uint32_t *base)
+uint8_t rsp_device::read_dmem_byte(uint32_t address)
{
- m_dmem32 = base;
- m_dmem16 = (uint16_t*)base;
- m_dmem8 = (uint8_t*)base;
+ return m_dcache.read_byte(address);
}
-uint8_t rsp_device::DM_READ8(uint32_t address)
+uint16_t rsp_device::read_dmem_word(uint32_t address)
{
- uint8_t ret = m_dmem8[BYTE4_XOR_BE(address & 0xfff)];
- //printf("R8:%08x=%02x\n", address, ret);
- return ret;
+ return m_dcache.read_word_unaligned(address);
}
-uint16_t rsp_device::DM_READ16(uint32_t address)
+uint32_t rsp_device::read_dmem_dword(uint32_t address)
{
- uint16_t ret;
- address &= 0xfff;
- ret = m_dmem8[BYTE4_XOR_BE(address)] << 8;
- ret |= m_dmem8[BYTE4_XOR_BE(address + 1)];
- //printf("R16:%08x=%04x\n", address, ret);
- return ret;
+ return m_dcache.read_dword_unaligned(address);
}
-uint32_t rsp_device::DM_READ32(uint32_t address)
+void rsp_device::write_dmem_byte(uint32_t address, uint8_t data)
{
- uint32_t ret;
- address &= 0xfff;
- ret = m_dmem8[BYTE4_XOR_BE(address)] << 24;
- ret |= m_dmem8[BYTE4_XOR_BE(address + 1)] << 16;
- ret |= m_dmem8[BYTE4_XOR_BE(address + 2)] << 8;
- ret |= m_dmem8[BYTE4_XOR_BE(address + 3)];
- //printf("R32:%08x=%08x\n", address, ret);
- return ret;
+ m_dcache.write_byte(address, data);
}
-void rsp_device::DM_WRITE8(uint32_t address, uint8_t data)
+void rsp_device::write_dmem_word(uint32_t address, uint16_t data)
{
- address &= 0xfff;
- m_dmem8[BYTE4_XOR_BE(address)] = data;
- //printf("W8:%08x=%02x\n", address, data);
+ m_dcache.write_word_unaligned(address, data);
}
-void rsp_device::DM_WRITE16(uint32_t address, uint16_t data)
+void rsp_device::write_dmem_dword(uint32_t address, uint32_t data)
{
- address &= 0xfff;
- m_dmem8[BYTE4_XOR_BE(address)] = data >> 8;
- m_dmem8[BYTE4_XOR_BE(address + 1)] = data & 0xff;
- //printf("W16:%08x=%04x\n", address, data);
-}
-
-void rsp_device::DM_WRITE32(uint32_t address, uint32_t data)
-{
- address &= 0xfff;
- m_dmem8[BYTE4_XOR_BE(address)] = data >> 24;
- m_dmem8[BYTE4_XOR_BE(address + 1)] = (data >> 16) & 0xff;
- m_dmem8[BYTE4_XOR_BE(address + 2)] = (data >> 8) & 0xff;
- m_dmem8[BYTE4_XOR_BE(address + 3)] = data & 0xff;
- //printf("W32:%08x=%08x\n", address, data);
-}
-
-uint8_t rsp_device::READ8(uint32_t address)
-{
- uint8_t ret;
- address &= 0xfff;
- ret = m_program->read_byte(address);
- //printf("R8:%08x=%02x\n", address, ret);
- return ret;
-}
-
-uint16_t rsp_device::READ16(uint32_t address)
-{
- uint16_t ret;
- address &= 0xfff;
-
- ret = (m_program->read_byte(address) << 8) | (m_program->read_byte(address + 1) & 0xff);
-
- //printf("R16:%08x=%04x\n", address, ret);
- return ret;
-}
-
-uint32_t rsp_device::READ32(uint32_t address)
-{
- uint32_t ret;
- address &= 0xfff;
-
- ret = (m_program->read_byte(address) << 24) |
- (m_program->read_byte(address + 1) << 16) |
- (m_program->read_byte(address + 2) << 8) |
- (m_program->read_byte(address + 3) << 0);
-
- //printf("R32:%08x=%08x\n", address, ret);
- return ret;
-}
-
-void rsp_device::WRITE8(uint32_t address, uint8_t data)
-{
- address &= 0xfff;
- m_program->write_byte(address, data);
- //printf("W8:%08x=%02x\n", address, data);
-}
-
-void rsp_device::WRITE16(uint32_t address, uint16_t data)
-{
- address &= 0xfff;
-
- m_program->write_byte(address, data >> 8);
- m_program->write_byte(address + 1, data & 0xff);
- //printf("W16:%08x=%04x\n", address, data);
-}
-
-void rsp_device::WRITE32(uint32_t address, uint32_t data)
-{
- address &= 0xfff;
-
- m_program->write_byte(address, data >> 24);
- m_program->write_byte(address + 1, (data >> 16) & 0xff);
- m_program->write_byte(address + 2, (data >> 8) & 0xff);
- m_program->write_byte(address + 3, data & 0xff);
- //printf("W32:%08x=%08x\n", address, data);
+ m_dcache.write_dword_unaligned(address, data);
}
/*****************************************************************************/
@@ -353,7 +241,7 @@ void rsp_device::unimplemented_opcode(uint32_t op)
for (i=0; i < 0x1000; i++)
{
- fputc(READ8(rsp, 0x04000000 + i), dmem);
+ fputc(read_dmem_byte(i), dmem);
}
fclose(dmem);
}
@@ -364,108 +252,83 @@ void rsp_device::unimplemented_opcode(uint32_t op)
/*****************************************************************************/
-void rsp_device::resolve_cb()
-{
- m_dp_reg_r_func.resolve();
- m_dp_reg_w_func.resolve();
- m_sp_reg_r_func.resolve();
- m_sp_reg_w_func.resolve();
- m_sp_set_status_func.resolve();
-}
-
void rsp_device::device_start()
{
- m_isdrc = allow_drc();
- m_rsp_state = (internal_rsp_state *)m_cache.alloc_near(sizeof(internal_rsp_state));
-
if (LOG_INSTRUCTION_EXECUTION)
m_exec_output = fopen("rsp_execute.txt", "wt");
- m_program = &space(AS_PROGRAM);
- m_pcache = m_program->cache<2, 0, ENDIANNESS_BIG>();
- resolve_cb();
-
- if (m_isdrc)
- m_cop2 = std::make_unique<cop2_drc>(*this, machine());
- else
- m_cop2 = std::make_unique<cop2>(*this, machine());
-
- m_cop2->init();
- m_cop2->start();
+ space(AS_PROGRAM).cache(m_icache);
+ space(AS_PROGRAM).specific(m_imem);
+ space(AS_DATA).cache(m_dcache);
+ space(AS_DATA).specific(m_dmem);
- // RSP registers should power on to a random state
for (int regIdx = 0; regIdx < 32; regIdx++)
- m_rsp_state->r[regIdx] = 0;
-
- m_sr = RSP_STATUS_HALT;
- m_step_count = 0;
-
- /* initialize the UML generator */
- uint32_t drc_flags = 0;
- m_drcuml = std::make_unique<drcuml_state>(*this, m_cache, drc_flags, 8, 32, 2);
+ m_r[regIdx] = 0;
- /* add symbols for our stuff */
- m_drcuml->symbol_add(&m_rsp_state->pc, sizeof(m_rsp_state->pc), "pc");
- m_drcuml->symbol_add(&m_rsp_state->icount, sizeof(m_rsp_state->icount), "icount");
- for (int regnum = 0; regnum < 32; regnum++)
+ for(auto & elem : m_v)
{
- char buf[10];
- sprintf(buf, "r%d", regnum);
- m_drcuml->symbol_add(&m_rsp_state->r[regnum], sizeof(m_rsp_state->r[regnum]), buf);
+ elem.d[0] = 0;
+ elem.d[1] = 0;
}
- m_drcuml->symbol_add(&m_rsp_state->arg0, sizeof(m_rsp_state->arg0), "arg0");
- m_drcuml->symbol_add(&m_rsp_state->arg1, sizeof(m_rsp_state->arg1), "arg1");
- m_drcuml->symbol_add(&m_arg2, sizeof(m_arg2), "arg2");
- m_drcuml->symbol_add(&m_arg3, sizeof(m_arg3), "arg3");
- m_drcuml->symbol_add(&m_numcycles, sizeof(m_numcycles), "numcycles");
- /* initialize the front-end helper */
- m_drcfe = std::make_unique<frontend>(*this, COMPILE_BACKWARDS_BYTES, COMPILE_FORWARDS_BYTES, SINGLE_INSTRUCTION_MODE ? 1 : COMPILE_MAX_SEQUENCE);
+ m_vcarry = 0;
+ m_vcompare = 0;
+ m_vclip1 = 0;
+ m_vzero = 0;
+ m_vclip2 = 0;
- /* compute the register parameters */
- for (int regnum = 0; regnum < 32; regnum++)
+ m_reciprocal_res = 0;
+ m_reciprocal_high = 0;
+ m_ideduct = 0;
+ m_scalar_busy = false;
+ m_vector_busy = false;
+ m_paired_busy = false;
+
+ for(auto & elem : m_accum)
{
- m_regmap[regnum] = (regnum == 0) ? uml::parameter(0) : uml::parameter::make_memory(&m_rsp_state->r[regnum]);
+ elem.q = 0;
}
- /* mark the cache dirty so it is updated on next execute */
- m_cache_dirty = true;
-
- state_add( RSP_PC, "PC", m_debugger_temp).callimport().callexport().formatstr("%08X");
- state_add( RSP_R0, "R0", m_rsp_state->r[0]).formatstr("%08X");
- state_add( RSP_R1, "R1", m_rsp_state->r[1]).formatstr("%08X");
- state_add( RSP_R2, "R2", m_rsp_state->r[2]).formatstr("%08X");
- state_add( RSP_R3, "R3", m_rsp_state->r[3]).formatstr("%08X");
- state_add( RSP_R4, "R4", m_rsp_state->r[4]).formatstr("%08X");
- state_add( RSP_R5, "R5", m_rsp_state->r[5]).formatstr("%08X");
- state_add( RSP_R6, "R6", m_rsp_state->r[6]).formatstr("%08X");
- state_add( RSP_R7, "R7", m_rsp_state->r[7]).formatstr("%08X");
- state_add( RSP_R8, "R8", m_rsp_state->r[8]).formatstr("%08X");
- state_add( RSP_R9, "R9", m_rsp_state->r[9]).formatstr("%08X");
- state_add( RSP_R10, "R10", m_rsp_state->r[10]).formatstr("%08X");
- state_add( RSP_R11, "R11", m_rsp_state->r[11]).formatstr("%08X");
- state_add( RSP_R12, "R12", m_rsp_state->r[12]).formatstr("%08X");
- state_add( RSP_R13, "R13", m_rsp_state->r[13]).formatstr("%08X");
- state_add( RSP_R14, "R14", m_rsp_state->r[14]).formatstr("%08X");
- state_add( RSP_R15, "R15", m_rsp_state->r[15]).formatstr("%08X");
- state_add( RSP_R16, "R16", m_rsp_state->r[16]).formatstr("%08X");
- state_add( RSP_R17, "R17", m_rsp_state->r[17]).formatstr("%08X");
- state_add( RSP_R18, "R18", m_rsp_state->r[18]).formatstr("%08X");
- state_add( RSP_R19, "R19", m_rsp_state->r[19]).formatstr("%08X");
- state_add( RSP_R20, "R20", m_rsp_state->r[20]).formatstr("%08X");
- state_add( RSP_R21, "R21", m_rsp_state->r[21]).formatstr("%08X");
- state_add( RSP_R22, "R22", m_rsp_state->r[22]).formatstr("%08X");
- state_add( RSP_R23, "R23", m_rsp_state->r[23]).formatstr("%08X");
- state_add( RSP_R24, "R24", m_rsp_state->r[24]).formatstr("%08X");
- state_add( RSP_R25, "R25", m_rsp_state->r[25]).formatstr("%08X");
- state_add( RSP_R26, "R26", m_rsp_state->r[26]).formatstr("%08X");
- state_add( RSP_R27, "R27", m_rsp_state->r[27]).formatstr("%08X");
- state_add( RSP_R28, "R28", m_rsp_state->r[28]).formatstr("%08X");
- state_add( RSP_R29, "R29", m_rsp_state->r[29]).formatstr("%08X");
- state_add( RSP_R30, "R30", m_rsp_state->r[30]).formatstr("%08X");
- state_add( RSP_R31, "R31", m_rsp_state->r[31]).formatstr("%08X");
+ m_pc = 0;
+ m_nextpc = 0xffff;
+ m_sr = RSP_STATUS_HALT;
+ m_step_count = 0;
+
+ state_add( RSP_PC, "PC", m_pc).callimport().callexport().formatstr("%08X");
+ state_add( RSP_R0, "R0", m_r[0]).formatstr("%08X");
+ state_add( RSP_R1, "R1", m_r[1]).formatstr("%08X");
+ state_add( RSP_R2, "R2", m_r[2]).formatstr("%08X");
+ state_add( RSP_R3, "R3", m_r[3]).formatstr("%08X");
+ state_add( RSP_R4, "R4", m_r[4]).formatstr("%08X");
+ state_add( RSP_R5, "R5", m_r[5]).formatstr("%08X");
+ state_add( RSP_R6, "R6", m_r[6]).formatstr("%08X");
+ state_add( RSP_R7, "R7", m_r[7]).formatstr("%08X");
+ state_add( RSP_R8, "R8", m_r[8]).formatstr("%08X");
+ state_add( RSP_R9, "R9", m_r[9]).formatstr("%08X");
+ state_add( RSP_R10, "R10", m_r[10]).formatstr("%08X");
+ state_add( RSP_R11, "R11", m_r[11]).formatstr("%08X");
+ state_add( RSP_R12, "R12", m_r[12]).formatstr("%08X");
+ state_add( RSP_R13, "R13", m_r[13]).formatstr("%08X");
+ state_add( RSP_R14, "R14", m_r[14]).formatstr("%08X");
+ state_add( RSP_R15, "R15", m_r[15]).formatstr("%08X");
+ state_add( RSP_R16, "R16", m_r[16]).formatstr("%08X");
+ state_add( RSP_R17, "R17", m_r[17]).formatstr("%08X");
+ state_add( RSP_R18, "R18", m_r[18]).formatstr("%08X");
+ state_add( RSP_R19, "R19", m_r[19]).formatstr("%08X");
+ state_add( RSP_R20, "R20", m_r[20]).formatstr("%08X");
+ state_add( RSP_R21, "R21", m_r[21]).formatstr("%08X");
+ state_add( RSP_R22, "R22", m_r[22]).formatstr("%08X");
+ state_add( RSP_R23, "R23", m_r[23]).formatstr("%08X");
+ state_add( RSP_R24, "R24", m_r[24]).formatstr("%08X");
+ state_add( RSP_R25, "R25", m_r[25]).formatstr("%08X");
+ state_add( RSP_R26, "R26", m_r[26]).formatstr("%08X");
+ state_add( RSP_R27, "R27", m_r[27]).formatstr("%08X");
+ state_add( RSP_R28, "R28", m_r[28]).formatstr("%08X");
+ state_add( RSP_R29, "R29", m_r[29]).formatstr("%08X");
+ state_add( RSP_R30, "R30", m_r[30]).formatstr("%08X");
+ state_add( RSP_R31, "R31", m_r[31]).formatstr("%08X");
state_add( RSP_SR, "SR", m_sr).formatstr("%08X");
- state_add( RSP_NEXTPC, "NPC", m_debugger_temp).callimport().callexport().formatstr("%08X");
+ state_add( RSP_NEXTPC, "NPC", m_nextpc).callimport().callexport().formatstr("%04X");
state_add( RSP_STEPCNT, "STEP", m_step_count).formatstr("%08X");
state_add( RSP_V0, "V0", m_debugger_temp).formatstr("%39s");
@@ -501,12 +364,11 @@ void rsp_device::device_start()
state_add( RSP_V30, "V30", m_debugger_temp).formatstr("%39s");
state_add( RSP_V31, "V31", m_debugger_temp).formatstr("%39s");
- state_add( STATE_GENPC, "GENPC", m_debugger_temp).callimport().callexport().noshow();
- state_add( STATE_GENPCBASE, "CURPC", m_rsp_state->pc).noshow();
- state_add( STATE_GENFLAGS, "GENFLAGS", m_debugger_temp).formatstr("%1s").noshow();
- state_add( STATE_GENSP, "GENSP", m_rsp_state->r[31]).noshow();
+ state_add( STATE_GENPC, "GENPC", m_pc).noshow();
+ state_add( STATE_GENPCBASE, "CURPC", m_pc).noshow();
+ state_add( STATE_GENFLAGS, "GENFLAGS", m_r[31]).formatstr("%1s").noshow();
- set_icountptr(m_rsp_state->icount);
+ set_icountptr(m_icount);
}
void rsp_device::state_import(const device_state_entry &entry)
@@ -515,15 +377,15 @@ void rsp_device::state_import(const device_state_entry &entry)
{
case STATE_GENPC:
case RSP_PC:
- m_rsp_state->pc = m_debugger_temp;
+ m_pc = (uint16_t)m_pc_temp;
break;
case STATE_GENPCBASE:
- m_ppc = m_debugger_temp;
+ m_ppc = (uint16_t)m_ppc_temp;
break;
case RSP_NEXTPC:
- m_nextpc = m_debugger_temp;
+ m_nextpc = (uint16_t)m_nextpc_temp;
break;
}
}
@@ -535,15 +397,15 @@ void rsp_device::state_export(const device_state_entry &entry)
{
case STATE_GENPC:
case RSP_PC:
- m_debugger_temp = m_rsp_state->pc | 0x04000000;
+ m_pc_temp = m_pc;
break;
case STATE_GENPCBASE:
- m_debugger_temp = m_ppc | 0x04000000;
+ m_ppc_temp = m_ppc;
break;
case RSP_NEXTPC:
- m_debugger_temp = m_nextpc | 0x04000000;
+ m_nextpc_temp = m_nextpc;
break;
}
}
@@ -551,13 +413,75 @@ void rsp_device::state_export(const device_state_entry &entry)
void rsp_device::state_string_export(const device_state_entry &entry, std::string &str) const
{
const int index = entry.index();
- if (index >= RSP_V0 && index <= RSP_V31)
+ switch (index)
{
- m_cop2->state_string_export(index, str);
- }
- else if (index == STATE_GENFLAGS)
- {
- str = "";
+ case RSP_V0:
+ str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[ 0].w[0], m_v[ 0].w[1], m_v[ 0].w[2], m_v[ 0].w[3], m_v[ 0].w[4], m_v[ 0].w[5], m_v[ 0].w[6], m_v[ 0].w[7]); break;
+ case RSP_V1:
+ str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[ 1].w[0], m_v[ 1].w[1], m_v[ 1].w[2], m_v[ 1].w[3], m_v[ 1].w[4], m_v[ 1].w[5], m_v[ 1].w[6], m_v[ 1].w[7]); break;
+ case RSP_V2:
+ str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[ 2].w[0], m_v[ 2].w[1], m_v[ 2].w[2], m_v[ 2].w[3], m_v[ 2].w[4], m_v[ 2].w[5], m_v[ 2].w[6], m_v[ 2].w[7]); break;
+ case RSP_V3:
+ str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[ 3].w[0], m_v[ 3].w[1], m_v[ 3].w[2], m_v[ 3].w[3], m_v[ 3].w[4], m_v[ 3].w[5], m_v[ 3].w[6], m_v[ 3].w[7]); break;
+ case RSP_V4:
+ str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[ 4].w[0], m_v[ 4].w[1], m_v[ 4].w[2], m_v[ 4].w[3], m_v[ 4].w[4], m_v[ 4].w[5], m_v[ 4].w[6], m_v[ 4].w[7]); break;
+ case RSP_V5:
+ str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[ 5].w[0], m_v[ 5].w[1], m_v[ 5].w[2], m_v[ 5].w[3], m_v[ 5].w[4], m_v[ 5].w[5], m_v[ 5].w[6], m_v[ 5].w[7]); break;
+ case RSP_V6:
+ str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[ 6].w[0], m_v[ 6].w[1], m_v[ 6].w[2], m_v[ 6].w[3], m_v[ 6].w[4], m_v[ 6].w[5], m_v[ 6].w[6], m_v[ 6].w[7]); break;
+ case RSP_V7:
+ str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[ 7].w[0], m_v[ 7].w[1], m_v[ 7].w[2], m_v[ 7].w[3], m_v[ 7].w[4], m_v[ 7].w[5], m_v[ 7].w[6], m_v[ 7].w[7]); break;
+ case RSP_V8:
+ str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[ 8].w[0], m_v[ 8].w[1], m_v[ 8].w[2], m_v[ 8].w[3], m_v[ 8].w[4], m_v[ 8].w[5], m_v[ 8].w[6], m_v[ 8].w[7]); break;
+ case RSP_V9:
+ str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[ 9].w[0], m_v[ 9].w[1], m_v[ 9].w[2], m_v[ 9].w[3], m_v[ 9].w[4], m_v[ 9].w[5], m_v[ 9].w[6], m_v[ 9].w[7]); break;
+ case RSP_V10:
+ str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[10].w[0], m_v[10].w[1], m_v[10].w[2], m_v[10].w[3], m_v[10].w[4], m_v[10].w[5], m_v[10].w[6], m_v[10].w[7]); break;
+ case RSP_V11:
+ str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[11].w[0], m_v[11].w[1], m_v[11].w[2], m_v[11].w[3], m_v[11].w[4], m_v[11].w[5], m_v[11].w[6], m_v[11].w[7]); break;
+ case RSP_V12:
+ str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[12].w[0], m_v[12].w[1], m_v[12].w[2], m_v[12].w[3], m_v[12].w[4], m_v[12].w[5], m_v[12].w[6], m_v[12].w[7]); break;
+ case RSP_V13:
+ str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[13].w[0], m_v[13].w[1], m_v[13].w[2], m_v[13].w[3], m_v[13].w[4], m_v[13].w[5], m_v[13].w[6], m_v[13].w[7]); break;
+ case RSP_V14:
+ str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[14].w[0], m_v[14].w[1], m_v[14].w[2], m_v[14].w[3], m_v[14].w[4], m_v[14].w[5], m_v[14].w[6], m_v[14].w[7]); break;
+ case RSP_V15:
+ str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[15].w[0], m_v[15].w[1], m_v[15].w[2], m_v[15].w[3], m_v[15].w[4], m_v[15].w[5], m_v[15].w[6], m_v[15].w[7]); break;
+ case RSP_V16:
+ str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[16].w[0], m_v[16].w[1], m_v[16].w[2], m_v[16].w[3], m_v[16].w[4], m_v[16].w[5], m_v[16].w[6], m_v[16].w[7]); break;
+ case RSP_V17:
+ str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[17].w[0], m_v[17].w[1], m_v[17].w[2], m_v[17].w[3], m_v[17].w[4], m_v[17].w[5], m_v[17].w[6], m_v[17].w[7]); break;
+ case RSP_V18:
+ str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[18].w[0], m_v[18].w[1], m_v[18].w[2], m_v[18].w[3], m_v[18].w[4], m_v[18].w[5], m_v[18].w[6], m_v[18].w[7]); break;
+ case RSP_V19:
+ str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[19].w[0], m_v[19].w[1], m_v[19].w[2], m_v[19].w[3], m_v[19].w[4], m_v[19].w[5], m_v[19].w[6], m_v[19].w[7]); break;
+ case RSP_V20:
+ str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[20].w[0], m_v[20].w[1], m_v[20].w[2], m_v[20].w[3], m_v[20].w[4], m_v[20].w[5], m_v[20].w[6], m_v[20].w[7]); break;
+ case RSP_V21:
+ str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[21].w[0], m_v[21].w[1], m_v[21].w[2], m_v[21].w[3], m_v[21].w[4], m_v[21].w[5], m_v[21].w[6], m_v[21].w[7]); break;
+ case RSP_V22:
+ str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[22].w[0], m_v[22].w[1], m_v[22].w[2], m_v[22].w[3], m_v[22].w[4], m_v[22].w[5], m_v[22].w[6], m_v[22].w[7]); break;
+ case RSP_V23:
+ str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[23].w[0], m_v[23].w[1], m_v[23].w[2], m_v[23].w[3], m_v[23].w[4], m_v[23].w[5], m_v[23].w[6], m_v[23].w[7]); break;
+ case RSP_V24:
+ str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[24].w[0], m_v[24].w[1], m_v[24].w[2], m_v[24].w[3], m_v[24].w[4], m_v[24].w[5], m_v[24].w[6], m_v[24].w[7]); break;
+ case RSP_V25:
+ str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[25].w[0], m_v[25].w[1], m_v[25].w[2], m_v[25].w[3], m_v[25].w[4], m_v[25].w[5], m_v[25].w[6], m_v[25].w[7]); break;
+ case RSP_V26:
+ str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[26].w[0], m_v[26].w[1], m_v[26].w[2], m_v[26].w[3], m_v[26].w[4], m_v[26].w[5], m_v[26].w[6], m_v[26].w[7]); break;
+ case RSP_V27:
+ str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[27].w[0], m_v[27].w[1], m_v[27].w[2], m_v[27].w[3], m_v[27].w[4], m_v[27].w[5], m_v[27].w[6], m_v[27].w[7]); break;
+ case RSP_V28:
+ str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[28].w[0], m_v[28].w[1], m_v[28].w[2], m_v[28].w[3], m_v[28].w[4], m_v[28].w[5], m_v[28].w[6], m_v[28].w[7]); break;
+ case RSP_V29:
+ str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[29].w[0], m_v[29].w[1], m_v[29].w[2], m_v[29].w[3], m_v[29].w[4], m_v[29].w[5], m_v[29].w[6], m_v[29].w[7]); break;
+ case RSP_V30:
+ str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[30].w[0], m_v[30].w[1], m_v[30].w[2], m_v[30].w[3], m_v[30].w[4], m_v[30].w[5], m_v[30].w[6], m_v[30].w[7]); break;
+ case RSP_V31:
+ str = string_format("%04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X", m_v[31].w[0], m_v[31].w[1], m_v[31].w[2], m_v[31].w[3], m_v[31].w[4], m_v[31].w[5], m_v[31].w[6], m_v[31].w[7]); break;
+ case STATE_GENFLAGS:
+ str = "";
+ break;
}
}
@@ -582,21 +506,11 @@ void rsp_device::device_stop()
#if SAVE_DMEM
{
int i;
- FILE *dmem;
-#if 0
- dmem = fopen("rsp_dmem.txt", "wt");
-
- for (i=0; i < 0x1000; i+=4)
- {
- fprintf(dmem, "%08X: %08X\n", 0x04000000 + i, READ32(0x04000000 + i));
- }
- fclose(dmem);
-#endif
- dmem = fopen("rsp_dmem.bin", "wb");
+ FILE *dmem = fopen("rsp_dmem.bin", "wb");
for (i=0; i < 0x1000; i++)
{
- fputc(READ8(0x04000000 + i), dmem);
+ fputc(read_dmem_byte(i), dmem);
}
fclose(dmem);
}
@@ -609,70 +523,2381 @@ void rsp_device::device_stop()
void rsp_device::device_reset()
{
- m_nextpc = ~0;
+ m_nextpc = 0xffff;
}
-void rsp_device::execute_run()
+uint16_t rsp_device::SATURATE_ACCUM(int accum, int slice, uint16_t negative, uint16_t positive)
{
- if (m_isdrc)
+ if ((int16_t)m_accum[accum].w[SLICE_H] < 0)
+ {
+ if ((uint16_t)m_accum[accum].w[SLICE_H] != 0xffff)
+ {
+ return negative;
+ }
+ else
+ {
+ if ((int16_t)m_accum[accum].w[SLICE_M] >= 0)
+ {
+ return negative;
+ }
+ else
+ {
+ if (slice == 0)
+ {
+ return m_accum[accum].w[SLICE_L];
+ }
+ else if (slice == 1)
+ {
+ return m_accum[accum].w[SLICE_M];
+ }
+ }
+ }
+ }
+ else
{
- execute_run_drc();
- return;
+ if ((uint16_t)m_accum[accum].w[SLICE_H] != 0)
+ {
+ return positive;
+ }
+ else
+ {
+ if ((int16_t)m_accum[accum].w[SLICE_M] < 0)
+ {
+ return positive;
+ }
+ else
+ {
+ if (slice == 0)
+ {
+ return m_accum[accum].w[SLICE_L];
+ }
+ else
+ {
+ return m_accum[accum].w[SLICE_M];
+ }
+ }
+ }
}
+ return 0;
+}
- m_rsp_state->pc = 0x4001000 | (m_rsp_state->pc & 0xfff);
+void rsp_device::handle_vector_ops(uint32_t op)
+{
+ uint16_t vres[8];
+
+ // Opcode legend:
+ // E = VS2 element type
+ // S = VS1, Source vector 1
+ // T = VS2, Source vector 2
+ // D = Destination vector
- if( m_sr & ( RSP_STATUS_HALT | RSP_STATUS_BROKE ) )
+ switch (op & 0x3f)
{
- m_rsp_state->icount = std::min(m_rsp_state->icount, 0);
+ case 0x00: /* VMULF */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000000 |
+ // ------------------------------------------------------
+ //
+ // Multiplies signed integer by signed integer * 2
+
+ for (int i = 0; i < 8; i++)
+ {
+ int32_t s1 = m_v[VS1REG].s[i];
+ int32_t s2 = m_v[VS2REG].s[VEC_EL_2(EL, i)];
+
+ if (s1 == -32768 && s2 == -32768)
+ {
+ // overflow
+ m_accum[i].w[SLICE_H] = 0;
+ m_accum[i].w[SLICE_M] = -32768;
+ m_accum[i].w[SLICE_L] = -32768;
+ vres[i] = 0x7fff;
+ }
+ else
+ {
+ int64_t r = s1 * s2 * 2;
+ r += 0x8000; // rounding ?
+ m_accum[i].w[SLICE_H] = (r < 0) ? 0xffff : 0; // Sign-extend to 48-bit
+ m_accum[i].w[SLICE_M] = (int16_t)(r >> 16);
+ m_accum[i].w[SLICE_L] = (uint16_t)r;
+ vres[i] = m_accum[i].w[SLICE_M];
+ }
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x01: /* VMULU */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000001 |
+ // ------------------------------------------------------
+ //
+
+ for (int i = 0; i < 8; i++)
+ {
+ int32_t s1 = m_v[VS1REG].s[i];
+ int32_t s2 = m_v[VS2REG].s[VEC_EL_2(EL, i)];
+
+ int64_t r = s1 * s2 * 2;
+ r += 0x8000; // rounding ?
+
+ m_accum[i].w[SLICE_H] = (uint16_t)(r >> 32);
+ m_accum[i].w[SLICE_M] = (uint16_t)(r >> 16);
+ m_accum[i].w[SLICE_L] = (uint16_t)r;
+
+ if (r < 0)
+ {
+ vres[i] = 0;
+ }
+ else if (((int16_t)m_accum[i].w[SLICE_H] ^ (int16_t)m_accum[i].w[SLICE_M]) < 0)
+ {
+ vres[i] = -1;
+ }
+ else
+ {
+ vres[i] = m_accum[i].w[SLICE_M];
+ }
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x04: /* VMUDL */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000100 |
+ // ------------------------------------------------------
+ //
+ // Multiplies unsigned fraction by unsigned fraction
+ // Stores the higher 16 bits of the 32-bit result to accumulator
+ // The low slice of accumulator is stored into destination element
+
+ for (int i = 0; i < 8; i++)
+ {
+ uint32_t s1 = m_v[VS1REG].w[i];
+ uint32_t s2 = m_v[VS2REG].w[VEC_EL_2(EL, i)];
+ uint32_t r = s1 * s2;
+
+ m_accum[i].w[SLICE_H] = 0;
+ m_accum[i].w[SLICE_M] = 0;
+ m_accum[i].w[SLICE_L] = (uint16_t)(r >> 16);
+
+ vres[i] = m_accum[i].w[SLICE_L];
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x05: /* VMUDM */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000101 |
+ // ------------------------------------------------------
+ //
+ // Multiplies signed integer by unsigned fraction
+ // The result is stored into accumulator
+ // The middle slice of accumulator is stored into destination element
+
+ for (int i = 0; i < 8; i++)
+ {
+ int32_t s1 = m_v[VS1REG].s[i];
+ int32_t s2 = m_v[VS2REG].w[VEC_EL_2(EL, i)]; // not sign-extended
+ int32_t r = s1 * s2;
+
+ m_accum[i].w[SLICE_H] = (r < 0) ? 0xffff : 0; // sign-extend to 48-bit
+ m_accum[i].w[SLICE_M] = (int16_t)(r >> 16);
+ m_accum[i].w[SLICE_L] = (uint16_t)r;
+
+ vres[i] = m_accum[i].w[SLICE_M];
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x06: /* VMUDN */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000110 |
+ // ------------------------------------------------------
+ //
+ // Multiplies unsigned fraction by signed integer
+ // The result is stored into accumulator
+ // The low slice of accumulator is stored into destination element
+
+ for (int i = 0; i < 8; i++)
+ {
+ int32_t s1 = m_v[VS1REG].w[i]; // not sign-extended
+ int32_t s2 = m_v[VS2REG].s[VEC_EL_2(EL, i)];
+ int32_t r = s1 * s2;
+
+ m_accum[i].w[SLICE_H] = (r < 0) ? 0xffff : 0; // sign-extend to 48-bit
+ m_accum[i].w[SLICE_M] = (int16_t)(r >> 16);
+ m_accum[i].w[SLICE_L] = (uint16_t)(r);
+
+ vres[i] = m_accum[i].w[SLICE_L];
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x07: /* VMUDH */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000111 |
+ // ------------------------------------------------------
+ //
+ // Multiplies signed integer by signed integer
+ // The result is stored into highest 32 bits of accumulator, the low slice is zero
+ // The highest 32 bits of accumulator is saturated into destination element
+
+ for (int i = 0; i < 8; i++)
+ {
+ int32_t s1 = m_v[VS1REG].s[i];
+ int32_t s2 = m_v[VS2REG].s[VEC_EL_2(EL, i)];
+ int32_t r = s1 * s2;
+
+ m_accum[i].w[SLICE_H] = (int16_t)(r >> 16);
+ m_accum[i].w[SLICE_M] = (uint16_t)(r);
+ m_accum[i].w[SLICE_L] = 0;
+
+ if (r < -32768) r = -32768;
+ if (r > 32767) r = 32767;
+ vres[i] = (int16_t)(r);
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x08: /* VMACF */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001000 |
+ // ------------------------------------------------------
+ //
+ // Multiplies signed integer by signed integer * 2
+ // The result is added to accumulator
+
+ for (int i = 0; i < 8; i++)
+ {
+ int32_t s1 = m_v[VS1REG].s[i];
+ int32_t s2 = m_v[VS2REG].s[VEC_EL_2(EL, i)];
+ int32_t r = s1 * s2;
+
+ uint64_t q = (uint64_t)(uint16_t)m_accum[i].w[SLICE_LL];
+ q |= (((uint64_t)(uint16_t)m_accum[i].w[SLICE_L]) << 16);
+ q |= (((uint64_t)(uint16_t)m_accum[i].w[SLICE_M]) << 32);
+ q |= (((uint64_t)(uint16_t)m_accum[i].w[SLICE_H]) << 48);
+
+ q += (int64_t)(r) << 17;
+
+ m_accum[i].w[SLICE_LL] = (uint16_t)q;
+ m_accum[i].w[SLICE_L] = (uint16_t)(q >> 16);
+ m_accum[i].w[SLICE_M] = (uint16_t)(q >> 32);
+ m_accum[i].w[SLICE_H] = (uint16_t)(q >> 48);
+
+ vres[i] = SATURATE_ACCUM(i, 1, 0x8000, 0x7fff);
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x09: /* VMACU */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001001 |
+ // ------------------------------------------------------
+ //
+
+ for (int i = 0; i < 8; i++)
+ {
+ int32_t s1 = m_v[VS1REG].s[i];
+ int32_t s2 = m_v[VS2REG].s[VEC_EL_2(EL, i)];
+ int32_t r1 = s1 * s2;
+ uint32_t r2 = m_accum[i].w[SLICE_L] + ((uint16_t)r1 * 2);
+ uint32_t r3 = m_accum[i].w[SLICE_M] + (uint16_t)((r1 >> 16) * 2) + (uint16_t)(r2 >> 16);
+
+ m_accum[i].w[SLICE_L] = (uint16_t)r2;
+ m_accum[i].w[SLICE_M] = (uint16_t)r3;
+ m_accum[i].w[SLICE_H] += (uint16_t)(r3 >> 16) + (uint16_t)(r1 >> 31);
+
+ if ((int16_t)m_accum[i].w[SLICE_H] < 0)
+ {
+ vres[i] = 0;
+ }
+ else
+ {
+ if (m_accum[i].w[SLICE_H] != 0)
+ {
+ vres[i] = 0xffff;
+ }
+ else
+ {
+ if ((int16_t)m_accum[i].w[SLICE_M] < 0)
+ {
+ vres[i] = 0xffff;
+ }
+ else
+ {
+ vres[i] = m_accum[i].w[SLICE_M];
+ }
+ }
+ }
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x0c: /* VMADL */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001100 |
+ // ------------------------------------------------------
+ //
+ // Multiplies unsigned fraction by unsigned fraction
+ // Adds the higher 16 bits of the 32-bit result to accumulator
+ // The low slice of accumulator is stored into destination element
+
+ for (int i = 0; i < 8; i++)
+ {
+ uint32_t s1 = m_v[VS1REG].w[i];
+ uint32_t s2 = m_v[VS2REG].w[VEC_EL_2(EL, i)];
+ uint32_t r1 = s1 * s2;
+ uint32_t r2 = m_accum[i].w[SLICE_L] + (r1 >> 16);
+ uint32_t r3 = m_accum[i].w[SLICE_M] + (r2 >> 16);
+
+ m_accum[i].w[SLICE_L] = (uint16_t)r2;
+ m_accum[i].w[SLICE_M] = (uint16_t)r3;
+ m_accum[i].w[SLICE_H] += (int16_t)(r3 >> 16);
+
+ vres[i] = SATURATE_ACCUM(i, 0, 0x0000, 0xffff);
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x0d: /* VMADM */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001101 |
+ // ------------------------------------------------------
+ //
+ // Multiplies signed integer by unsigned fraction
+ // The result is added into accumulator
+ // The middle slice of accumulator is stored into destination element
+
+ for (int i = 0; i < 8; i++)
+ {
+ uint32_t s1 = m_v[VS1REG].s[i];
+ uint32_t s2 = m_v[VS2REG].w[VEC_EL_2(EL, i)]; // not sign-extended
+ uint32_t r1 = s1 * s2;
+ uint32_t r2 = (uint16_t)m_accum[i].w[SLICE_L] + (uint16_t)(r1);
+ uint32_t r3 = (uint16_t)m_accum[i].w[SLICE_M] + (r1 >> 16) + (r2 >> 16);
+
+ m_accum[i].w[SLICE_L] = (uint16_t)r2;
+ m_accum[i].w[SLICE_M] = (uint16_t)r3;
+ m_accum[i].w[SLICE_H] += (uint16_t)(r3 >> 16);
+ if ((int32_t)r1 < 0)
+ m_accum[i].w[SLICE_H] -= 1;
+
+ vres[i] = SATURATE_ACCUM(i, 1, 0x8000, 0x7fff);
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x0e: /* VMADN */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001110 |
+ // ------------------------------------------------------
+ //
+ // Multiplies unsigned fraction by signed integer
+ // The result is added into accumulator
+ // The low slice of accumulator is stored into destination element
+
+ for (int i = 0; i < 8; i++)
+ {
+ int32_t s1 = m_v[VS1REG].w[i]; // not sign-extended
+ int32_t s2 = m_v[VS2REG].s[VEC_EL_2(EL, i)];
+
+ uint64_t q = (uint64_t)m_accum[i].w[SLICE_LL];
+ q |= (((uint64_t)m_accum[i].w[SLICE_L]) << 16);
+ q |= (((uint64_t)m_accum[i].w[SLICE_M]) << 32);
+ q |= (((uint64_t)m_accum[i].w[SLICE_H]) << 48);
+ q += (int64_t)(s1*s2) << 16;
+
+ m_accum[i].w[SLICE_LL] = (uint16_t)q;
+ m_accum[i].w[SLICE_L] = (uint16_t)(q >> 16);
+ m_accum[i].w[SLICE_M] = (uint16_t)(q >> 32);
+ m_accum[i].w[SLICE_H] = (uint16_t)(q >> 48);
+
+ vres[i] = SATURATE_ACCUM(i, 0, 0x0000, 0xffff);
+ }
+ WRITEBACK_RESULT();
+
+ break;
+ }
+
+ case 0x0f: /* VMADH */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001111 |
+ // ------------------------------------------------------
+ //
+ // Multiplies signed integer by signed integer
+ // The result is added into highest 32 bits of accumulator, the low slice is zero
+ // The highest 32 bits of accumulator is saturated into destination element
+
+ for (int i = 0; i < 8; i++)
+ {
+ int32_t s1 = m_v[VS1REG].s[i];
+ int32_t s2 = m_v[VS2REG].s[VEC_EL_2(EL, i)];
+
+ int32_t accum = (uint32_t)(uint16_t)m_accum[i].w[SLICE_M];
+ accum |= ((uint32_t)((uint16_t)m_accum[i].w[SLICE_H])) << 16;
+ accum += s1 * s2;
+
+ m_accum[i].w[SLICE_H] = (uint16_t)(accum >> 16);
+ m_accum[i].w[SLICE_M] = (uint16_t)accum;
+
+ vres[i] = SATURATE_ACCUM(i, 1, 0x8000, 0x7fff);
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x10: /* VADD */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 010000 |
+ // ------------------------------------------------------
+ //
+ // Adds two vector registers and carry flag, the result is saturated to 32767
+
+ // TODO: check VS2REG == VDREG
+
+ for (int i = 0; i < 8; i++)
+ {
+ int32_t s1 = m_v[VS1REG].s[i];
+ int32_t s2 = m_v[VS2REG].s[VEC_EL_2(EL, i)];
+ int32_t r = s1 + s2 + BIT(m_vcarry, i);
+
+ m_accum[i].w[SLICE_L] = (int16_t)r;
+
+ if (r > 32767) r = 32767;
+ if (r < -32768) r = -32768;
+ vres[i] = (int16_t)(r);
+ }
+ m_vzero = 0;
+ m_vcarry = 0;
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x11: /* VSUB */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 010001 |
+ // ------------------------------------------------------
+ //
+ // Subtracts two vector registers and carry flag, the result is saturated to -32768
+
+ // TODO: check VS2REG == VDREG
+
+ for (int i = 0; i < 8; i++)
+ {
+ int32_t s1 = m_v[VS1REG].s[i];
+ int32_t s2 = m_v[VS2REG].s[VEC_EL_2(EL, i)];
+ int32_t r = s1 - s2 - BIT(m_vcarry, i);
+
+ m_accum[i].w[SLICE_L] = (int16_t)r;
+
+ if (r > 32767) r = 32767;
+ if (r < -32768) r = -32768;
+
+ vres[i] = (int16_t)(r);
+ }
+ m_vzero = 0;
+ m_vcarry = 0;
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x13: /* VABS */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 010011 |
+ // ------------------------------------------------------
+ //
+ // Changes the sign of source register 2 if source register 1 is negative and stores
+ // the result to destination register
+
+ for (int i = 0; i < 8; i++)
+ {
+ int16_t s1 = m_v[VS1REG].s[i];
+ int16_t s2 = m_v[VS2REG].s[VEC_EL_2(EL, i)];
+
+ if (s1 < 0)
+ {
+ if (s2 == -32768)
+ {
+ vres[i] = 32767;
+ }
+ else
+ {
+ vres[i] = -s2;
+ }
+ }
+ else if (s1 > 0)
+ {
+ vres[i] = s2;
+ }
+ else
+ {
+ vres[i] = 0;
+ }
+
+ m_accum[i].w[SLICE_L] = vres[i];
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x14: /* VADDC */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 010100 |
+ // ------------------------------------------------------
+ //
+ // Adds two vector registers, the carry out is stored into carry register
+
+ // TODO: check VS2REG = VDREG
+
+ m_vzero = 0;
+ m_vcarry = 0;
+
+ for (int i = 0; i < 8; i++)
+ {
+ int32_t s1 = m_v[VS1REG].w[i];
+ int32_t s2 = m_v[VS2REG].w[VEC_EL_2(EL, i)];
+ int32_t r = s1 + s2;
+
+ vres[i] = (int16_t)r;
+ m_accum[i].w[SLICE_L] = (int16_t)r;
+
+ if (r & 0xffff0000)
+ {
+ m_vcarry |= 1 << i;
+ }
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x15: /* VSUBC */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 010101 |
+ // ------------------------------------------------------
+ //
+ // Subtracts two vector registers, the carry out is stored into carry register
+
+ // TODO: check VS2REG = VDREG
+
+ m_vzero = 0;
+ m_vcarry = 0;
+
+ for (int i = 0; i < 8; i++)
+ {
+ int32_t s1 = m_v[VS1REG].w[i];
+ int32_t s2 = m_v[VS2REG].w[VEC_EL_2(EL, i)];
+ int32_t r = s1 - s2;
+
+ vres[i] = (int16_t)(r);
+ m_accum[i].w[SLICE_L] = (uint16_t)r;
+
+ if ((uint16_t)r != 0)
+ {
+ m_vzero |= 1 << i;
+ }
+ if (r & 0xffff0000)
+ {
+ m_vcarry |= 1 << i;
+ }
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x1d: /* VSAW */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 011101 |
+ // ------------------------------------------------------
+ //
+ // Stores high, middle or low slice of accumulator to destination vector
+
+ switch (EL)
+ {
+ case 0x08: // VSAWH
+ {
+ for (int i = 0; i < 8; i++)
+ {
+ m_v[VDREG].w[i] = m_accum[i].w[SLICE_H];
+ }
+ break;
+ }
+ case 0x09: // VSAWM
+ {
+ for (int i = 0; i < 8; i++)
+ {
+ m_v[VDREG].w[i] = m_accum[i].w[SLICE_M];
+ }
+ break;
+ }
+ case 0x0a: // VSAWL
+ {
+ for (int i = 0; i < 8; i++)
+ {
+ m_v[VDREG].w[i] = m_accum[i].w[SLICE_L];
+ }
+ break;
+ }
+ default:
+ printf("RSP: VSAW: el = %d\n", EL);
+ break;
+ }
+ break;
+ }
+
+ case 0x20: /* VLT */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100000 |
+ // ------------------------------------------------------
+ //
+ // Sets compare flags if elements in VS1 are less than VS2
+ // Moves the element in VS2 to destination vector
+
+ m_vcompare = 0;
+ m_vclip2 = 0;
+
+ for (int i = 0; i < 8; i++)
+ {
+ int16_t s1 = m_v[VS1REG].s[i];
+ int16_t s2 = m_v[VS2REG].s[VEC_EL_2(EL, i)];
+ if (s1 < s2)
+ {
+ m_vcompare |= 1 << i;
+ }
+ else if (s1 == s2)
+ {
+ if (BIT(m_vzero & m_vcarry, i))
+ {
+ m_vcompare |= 1 << i;
+ }
+ }
+
+ if (BIT(m_vcompare, i))
+ {
+ vres[i] = s1;
+ }
+ else
+ {
+ vres[i] = s2;
+ }
+
+ m_accum[i].w[SLICE_L] = vres[i];
+ }
+
+ m_vzero = 0;
+ m_vcarry = 0;
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x21: /* VEQ */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100001 |
+ // ------------------------------------------------------
+ //
+ // Sets compare flags if elements in VS1 are equal with VS2
+ // Moves the element in VS2 to destination vector
+
+ m_vcompare = 0;
+ m_vclip2 = 0;
+
+ for (int i = 0; i < 8; i++)
+ {
+ int16_t s1 = m_v[VS1REG].s[i];
+ int16_t s2 = m_v[VS2REG].s[VEC_EL_2(EL, i)];
+
+ if ((s1 == s2) && !BIT(m_vzero, i))
+ {
+ m_vcompare |= 1 << i;
+ vres[i] = s1;
+ }
+ else
+ {
+ vres[i] = s2;
+ }
+ m_accum[i].w[SLICE_L] = vres[i];
+ }
+
+ m_vzero = 0;
+ m_vcarry = 0;
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x22: /* VNE */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100010 |
+ // ------------------------------------------------------
+ //
+ // Sets compare flags if elements in VS1 are not equal with VS2
+ // Moves the element in VS2 to destination vector
+
+ m_vcompare = 0;
+ m_vclip2 = 0;
+
+ for (int i = 0; i < 8; i++)
+ {
+ int16_t s1 = m_v[VS1REG].s[i];
+ int16_t s2 = m_v[VS2REG].s[VEC_EL_2(EL, i)];
+
+ if (s1 != s2 || BIT(m_vzero, i))
+ {
+ m_vcompare |= 1 << i;
+ vres[i] = s1;
+ }
+ else
+ {
+ vres[i] = s2;
+ }
+
+ m_accum[i].w[SLICE_L] = vres[i];
+ }
+
+ m_vzero = 0;
+ m_vcarry = 0;
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x23: /* VGE */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100011 |
+ // ------------------------------------------------------
+ //
+ // Sets compare flags if elements in VS1 are greater or equal with VS2
+ // Moves the element in VS2 to destination vector
+
+ m_vcompare = 0;
+ m_vclip2 = 0;
+
+ for (int i = 0; i < 8; i++)
+ {
+ int16_t s1 = m_v[VS1REG].s[i];
+ int16_t s2 = m_v[VS2REG].s[VEC_EL_2(EL, i)];
+
+ if ((s1 == s2 && (!BIT(m_vzero, i) || !BIT(m_vcarry, i))) || s1 > s2)
+ {
+ m_vcompare |= 1 << i;
+ vres[i] = s1;
+ }
+ else
+ {
+ vres[i] = s2;
+ }
+
+ m_accum[i].w[SLICE_L] = vres[i];
+ }
+
+ m_vzero = 0;
+ m_vcarry = 0;
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x24: /* VCL */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100100 |
+ // ------------------------------------------------------
+ //
+ // Vector clip low
+
+ for (int i = 0; i < 8; i++)
+ {
+ int16_t s1 = m_v[VS1REG].s[i];
+ int16_t s2 = m_v[VS2REG].s[VEC_EL_2(EL, i)];
+
+ if (BIT(m_vcarry, i)) // vco_lo
+ {
+ if (BIT(m_vzero, i)) // vco_hi
+ {
+ if (BIT(m_vcompare, i)) // vcc_lo
+ {
+ m_accum[i].w[SLICE_L] = -(uint16_t)s2;
+ }
+ else
+ {
+ m_accum[i].w[SLICE_L] = s1;
+ }
+ }
+ else
+ {
+ if (BIT(m_vclip1, i)) // vce
+ {
+ if (((uint32_t)(uint16_t)(s1) + (uint32_t)(uint16_t)(s2)) > 0x10000)
+ {
+ m_accum[i].w[SLICE_L] = s1;
+ m_vcompare &= ~(1 << i);
+ }
+ else
+ {
+ m_accum[i].w[SLICE_L] = -(uint16_t)s2;
+ m_vcompare |= 1 << i;
+ }
+ }
+ else
+ {
+ if (((uint32_t)(uint16_t)(s1) + (uint32_t)(uint16_t)(s2)) != 0)
+ {
+ m_accum[i].w[SLICE_L] = s1;
+ m_vcompare &= ~(1 << i);
+ }
+ else
+ {
+ m_accum[i].w[SLICE_L] = -(uint16_t)s2;
+ m_vcompare |= 1 << i;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (BIT(m_vzero, i)) // vco_hi
+ {
+ if (BIT(m_vclip2, i)) // vcc_hi
+ {
+ m_accum[i].w[SLICE_L] = s2;
+ }
+ else
+ {
+ m_accum[i].w[SLICE_L] = s1;
+ }
+ }
+ else
+ {
+ if (((int32_t)(uint16_t)s1 - (int32_t)(uint16_t)s2) >= 0)
+ {
+ m_accum[i].w[SLICE_L] = s2;
+ m_vclip2 |= 1 << i;
+ }
+ else
+ {
+ m_accum[i].w[SLICE_L] = s1;
+ m_vclip2 &= ~(1 << i);
+ }
+ }
+ }
+
+ vres[i] = m_accum[i].w[SLICE_L];
+ }
+
+ m_vzero = 0;
+ m_vcarry = 0;
+ m_vclip1 = 0;
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x25: /* VCH */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100101 |
+ // ------------------------------------------------------
+ //
+ // Vector clip high
+
+ m_vcarry = 0;
+ m_vcompare = 0;
+ m_vclip1 = 0;
+ m_vzero = 0;
+ m_vclip2 = 0;
+ uint32_t vce;
+
+ for (int i = 0; i < 8; i++)
+ {
+ int16_t s1 = m_v[VS1REG].s[i];
+ int16_t s2 = m_v[VS2REG].s[VEC_EL_2(EL, i)];
+
+ if ((s1 ^ s2) < 0)
+ {
+ vce = (s1 + s2 == -1);
+ m_vcarry |= 1 << i;
+ if (s2 < 0)
+ {
+ m_vclip2 |= 1 << i;
+ }
+
+ if (s1 + s2 <= 0)
+ {
+ m_vcompare |= 1 << i;
+ vres[i] = -((uint16_t)s2);
+ }
+ else
+ {
+ vres[i] = s1;
+ }
+
+ if (s1 + s2 != 0)
+ {
+ if (s1 != ~s2)
+ {
+ m_vzero |= 1 << i;
+ }
+ }
+ }
+ else
+ {
+ vce = 0;
+ if (s2 < 0)
+ {
+ m_vcompare |= 1 << i;
+ }
+ if (s1 - s2 >= 0)
+ {
+ m_vclip2 |= 1 << i;
+ vres[i] = s2;
+ }
+ else
+ {
+ vres[i] = s1;
+ }
+
+ if ((s1 - s2) != 0)
+ {
+ if (s1 != ~s2)
+ {
+ m_vzero |= 1 << i;
+ }
+ }
+ }
+
+ if (vce != 0)
+ {
+ m_vclip1 |= 1 << i;
+ }
+
+ m_accum[i].w[SLICE_L] = vres[i];
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x26: /* VCR */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100110 |
+ // ------------------------------------------------------
+ //
+ // Vector clip reverse
+
+ m_vcarry = 0;
+ m_vcompare = 0;
+ m_vclip1 = 0;
+ m_vzero = 0;
+ m_vclip2 = 0;
+
+ for (int i = 0; i < 8; i++)
+ {
+ int16_t s1 = m_v[VS1REG].s[i];
+ int16_t s2 = m_v[VS2REG].s[VEC_EL_2(EL, i)];
+
+ if ((int16_t)(s1 ^ s2) < 0)
+ {
+ if (s2 < 0)
+ {
+ m_vclip2 |= 1 << i;
+ }
+ if ((s1 + s2) <= 0)
+ {
+ m_accum[i].w[SLICE_L] = ~(uint16_t)s2;
+ m_vcompare |= 1 << i;
+ }
+ else
+ {
+ m_accum[i].w[SLICE_L] = s1;
+ }
+ }
+ else
+ {
+ if (s2 < 0)
+ {
+ m_vcompare |= 1 << i;
+ }
+ if ((s1 - s2) >= 0)
+ {
+ m_accum[i].w[SLICE_L] = s2;
+ m_vclip2 |= 1 << i;
+ }
+ else
+ {
+ m_accum[i].w[SLICE_L] = s1;
+ }
+ }
+
+ vres[i] = m_accum[i].w[SLICE_L];
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x27: /* VMRG */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100111 |
+ // ------------------------------------------------------
+ //
+ // Merges two vectors according to compare flags
+
+ for (int i = 0; i < 8; i++)
+ {
+ if (BIT(m_vcompare, i))
+ {
+ vres[i] = m_v[VS1REG].s[i];
+ }
+ else
+ {
+ vres[i] = m_v[VS2REG].s[VEC_EL_2(EL, i)];
+ }
+
+ m_accum[i].w[SLICE_L] = vres[i];
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x28: /* VAND */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101000 |
+ // ------------------------------------------------------
+ //
+ // Bitwise AND of two vector registers
+
+ for (int i = 0; i < 8; i++)
+ {
+ vres[i] = m_v[VS1REG].w[i] & m_v[VS2REG].w[VEC_EL_2(EL, i)];
+ m_accum[i].w[SLICE_L] = vres[i];
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x29: /* VNAND */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101001 |
+ // ------------------------------------------------------
+ //
+ // Bitwise NOT AND of two vector registers
+
+ for (int i = 0; i < 8; i++)
+ {
+ vres[i] = ~(m_v[VS1REG].w[i] & m_v[VS2REG].w[VEC_EL_2(EL, i)]);
+ m_accum[i].w[SLICE_L] = vres[i];
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x2a: /* VOR */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101010 |
+ // ------------------------------------------------------
+ //
+ // Bitwise OR of two vector registers
+
+ for (int i = 0; i < 8; i++)
+ {
+ vres[i] = m_v[VS1REG].w[i] | m_v[VS2REG].w[VEC_EL_2(EL, i)];
+ m_accum[i].w[SLICE_L] = vres[i];
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x2b: /* VNOR */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101011 |
+ // ------------------------------------------------------
+ //
+ // Bitwise NOT OR of two vector registers
+
+ for (int i = 0; i < 8; i++)
+ {
+ vres[i] = ~(m_v[VS1REG].w[i] | m_v[VS2REG].w[VEC_EL_2(EL, i)]);
+ m_accum[i].w[SLICE_L] = vres[i];
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x2c: /* VXOR */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101100 |
+ // ------------------------------------------------------
+ //
+ // Bitwise XOR of two vector registers
+
+ for (int i = 0; i < 8; i++)
+ {
+ vres[i] = m_v[VS1REG].w[i] ^ m_v[VS2REG].w[VEC_EL_2(EL, i)];
+ m_accum[i].w[SLICE_L] = vres[i];
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x2d: /* VNXOR */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101101 |
+ // ------------------------------------------------------
+ //
+ // Bitwise NOT XOR of two vector registers
+
+ for (int i = 0; i < 8; i++)
+ {
+ vres[i] = ~(m_v[VS1REG].w[i] ^ m_v[VS2REG].w[VEC_EL_2(EL, i)]);
+ m_accum[i].w[SLICE_L] = vres[i];
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x2e: /* V056 (Reserved) */
+ case 0x2f: /* V057 (Reserved) */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101101 |
+ // ------------------------------------------------------
+ //
+ // Reserved Opcode
+ // Appears to simply store the unsigned 16-bit sum of vector elements into low accumulator slice.
+ // Zeroes destination vector.
+
+ for (int i = 0; i < 8; i++)
+ {
+ vres[i] = 0;
+ uint16_t e1 = m_v[VS1REG].w[i];
+ uint16_t e2 = m_v[VS2REG].w[VEC_EL_2(EL, i)];
+ m_accum[i].w[SLICE_L] = e1 + e2;
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x30: /* VRCP */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110000 |
+ // ------------------------------------------------------
+ //
+ // Calculates reciprocal
+
+ int32_t shifter = 0;
+
+ int32_t rec = m_v[VS2REG].s[EL & 7];
+ int32_t datainput = (rec < 0) ? (-rec) : rec;
+ if (datainput)
+ {
+ for (int i = 0; i < 32; i++)
+ {
+ if (datainput & (1 << ((~i) & 0x1f)))
+ {
+ shifter = i;
+ break;
+ }
+ }
+ }
+ else
+ {
+ shifter = 0x10;
+ }
+
+ int32_t address = ((datainput << shifter) & 0x7fc00000) >> 22;
+ int32_t fetchval = rsp_divtable[address];
+ int32_t temp = (0x40000000 | (fetchval << 14)) >> ((~shifter) & 0x1f);
+ if (rec < 0)
+ {
+ temp = ~temp;
+ }
+ if (!rec)
+ {
+ temp = 0x7fffffff;
+ }
+ else if (rec == 0xffff8000)
+ {
+ temp = 0xffff0000;
+ }
+ rec = temp;
+
+ m_reciprocal_res = rec;
+ m_dp_allowed = 0;
+
+ m_v[VDREG].w[VS1REG & 7] = (uint16_t)(rec & 0xffff);
+
+ for (int i = 0; i < 8; i++)
+ {
+ m_accum[i].w[SLICE_L] = m_v[VS2REG].w[VEC_EL_2(EL, i)];
+ }
+ break;
+ }
+
+ case 0x31: /* VRCPL */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110001 |
+ // ------------------------------------------------------
+ //
+ // Calculates reciprocal low part
+
+ int32_t shifter = 0;
+
+ int32_t rec = m_v[VS2REG].s[EL & 7];
+ int32_t datainput = rec;
+
+ if (m_dp_allowed)
+ {
+ rec = (rec & 0x0000ffff) | m_reciprocal_high;
+ datainput = rec;
+
+ if (rec < 0)
+ {
+ if (rec < -32768)
+ {
+ datainput = ~datainput;
+ }
+ else
+ {
+ datainput = -datainput;
+ }
+ }
+ }
+ else if (datainput < 0)
+ {
+ datainput = -datainput;
+
+ shifter = 0x10;
+ }
+
+
+ for (int i = 0; i < 32; i++)
+ {
+ if (datainput & (1 << ((~i) & 0x1f)))
+ {
+ shifter = i;
+ break;
+ }
+ }
+
+ int32_t address = ((datainput << shifter) & 0x7fc00000) >> 22;
+ int32_t fetchval = rsp_divtable[address];
+ int32_t temp = (0x40000000 | (fetchval << 14)) >> ((~shifter) & 0x1f);
+ temp ^= rec >> 31;
+
+ if (!rec)
+ {
+ temp = 0x7fffffff;
+ }
+ else if (rec == 0xffff8000)
+ {
+ temp = 0xffff0000;
+ }
+ rec = temp;
+
+ m_reciprocal_res = rec;
+ m_dp_allowed = 0;
+
+ m_v[VDREG].w[VS1REG & 7] = (uint16_t)(rec & 0xffff);
+
+ for (int i = 0; i < 8; i++)
+ {
+ m_accum[i].w[SLICE_L] = m_v[VS2REG].w[VEC_EL_2(EL, i)];
+ }
+ break;
+ }
+
+ case 0x32: /* VRCPH */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110010 |
+ // ------------------------------------------------------
+ //
+ // Calculates reciprocal high part
+
+ m_reciprocal_high = m_v[VS2REG].w[EL & 7] << 16;
+ m_dp_allowed = 1;
+
+ for (int i = 0; i < 8; i++)
+ {
+ m_accum[i].w[SLICE_L] = m_v[VS2REG].w[VEC_EL_2(EL, i)];
+ }
+
+ m_v[VDREG].s[VS1REG & 7] = (int16_t)(m_reciprocal_res >> 16);
+ break;
+ }
+
+ case 0x33: /* VMOV */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110011 |
+ // ------------------------------------------------------
+ //
+ // Moves element from vector to destination vector
+
+ m_v[VDREG].w[VS1REG & 7] = m_v[VS2REG].w[VEC_EL_2(EL, VS1REG & 7)];
+ for (int i = 0; i < 8; i++)
+ {
+ m_accum[i].w[SLICE_L] = m_v[VS2REG].w[i];
+ }
+ break;
+ }
+
+ case 0x34: /* VRSQ */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110100 |
+ // ------------------------------------------------------
+ //
+ // Calculates reciprocal square-root
+
+ int32_t shifter = 0;
+
+ int32_t rec = m_v[VS2REG].s[EL & 7];
+ int32_t datainput = (rec < 0) ? (-rec) : rec;
+ if (datainput)
+ {
+ for (int i = 0; i < 32; i++)
+ {
+ if (datainput & (1 << (~i & 0x1f)))
+ {
+ shifter = i;
+ break;
+ }
+ }
+ }
+ else
+ {
+ shifter = 0x10;
+ }
+
+ int32_t address = ((datainput << shifter) & 0x7fc00000) >> 22;
+ address = ((address | 0x200) & 0x3fe) | (shifter & 1);
+
+ int32_t fetchval = rsp_divtable[address];
+ int32_t temp = (0x40000000 | (fetchval << 14)) >> (((~shifter) & 0x1f) >> 1);
+ if (rec < 0)
+ {
+ temp = ~temp;
+ }
+ if (!rec)
+ {
+ temp = 0x7fffffff;
+ }
+ else if (rec == 0xffff8000)
+ {
+ temp = 0xffff0000;
+ }
+ rec = temp;
+
+ m_reciprocal_res = rec;
+ m_dp_allowed = 0;
+
+ m_v[VDREG].w[VS1REG & 7] = (uint16_t)(rec & 0xffff);
+
+ for (int i = 0; i < 8; i++)
+ {
+ m_accum[i].w[SLICE_L] = m_v[VS2REG].w[VEC_EL_2(EL, i)];
+ }
+
+ break;
+ }
+
+ case 0x35: /* VRSQL */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110101 |
+ // ------------------------------------------------------
+ //
+ // Calculates reciprocal square-root low part
+
+ int32_t shifter = 0;
+ int32_t rec = m_v[VS2REG].s[EL & 7];
+ int32_t datainput = rec;
+
+ if (m_dp_allowed)
+ {
+ rec = (rec & 0x0000ffff) | m_reciprocal_high;
+ datainput = rec;
+
+ if (rec < 0)
+ {
+ if (rec < -32768)
+ {
+ datainput = ~datainput;
+ }
+ else
+ {
+ datainput = -datainput;
+ }
+ }
+ }
+ else if (datainput < 0)
+ {
+ datainput = -datainput;
+
+ shifter = 0x10;
+ }
+
+ if (datainput)
+ {
+ for (int i = 0; i < 32; i++)
+ {
+ if (datainput & (1 << ((~i) & 0x1f)))
+ {
+ shifter = i;
+ break;
+ }
+ }
+ }
+
+ int32_t address = ((datainput << shifter) & 0x7fc00000) >> 22;
+ address = ((address | 0x200) & 0x3fe) | (shifter & 1);
+
+ int32_t fetchval = rsp_divtable[address];
+ int32_t temp = (0x40000000 | (fetchval << 14)) >> (((~shifter) & 0x1f) >> 1);
+ temp ^= rec >> 31;
+
+ if (!rec)
+ {
+ temp = 0x7fffffff;
+ }
+ else if (rec == 0xffff8000)
+ {
+ temp = 0xffff0000;
+ }
+ rec = temp;
+
+ m_reciprocal_res = rec;
+ m_dp_allowed = 0;
+
+ m_v[VDREG].w[VS1REG & 7] = (uint16_t)(rec & 0xffff);
+
+ for (int i = 0; i < 8; i++)
+ {
+ m_accum[i].w[SLICE_L] = m_v[VS2REG].w[VEC_EL_2(EL, i)];
+ }
+
+ break;
+ }
+
+ case 0x36: /* VRSQH */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110110 |
+ // ------------------------------------------------------
+ //
+ // Calculates reciprocal square-root high part
+
+ m_reciprocal_high = m_v[VS2REG].w[EL & 7] << 16;
+ m_dp_allowed = 1;
+
+ for (int i = 0; i < 8; i++)
+ {
+ m_accum[i].w[SLICE_L] = m_v[VS2REG].w[VEC_EL_2(EL, i)];
+ }
+
+ m_v[VDREG].s[VS1REG & 7] = (int16_t)(m_reciprocal_res >> 16); // store high part
+ break;
+ }
+
+ case 0x37: /* VNOP */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110111 |
+ // ------------------------------------------------------
+ //
+ // Vector null instruction
+
+ break;
+ }
+
+ case 0x3b: /* V073 (Reserved) */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101101 |
+ // ------------------------------------------------------
+ //
+ // Reserved Opcode
+ // Appears to simply store the unsigned 16-bit sum of vector elements into low accumulator slice.
+ // Zeroes destination vector.
+
+ for (int i = 0; i < 8; i++)
+ {
+ vres[i] = 0;
+ uint16_t e1 = m_v[VS1REG].w[i];
+ uint16_t e2 = m_v[VS2REG].w[VEC_EL_2(EL, i)];
+ m_accum[i].w[SLICE_L] = e1 + e2;
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x3f: /* VNULL (Reserved) */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101101 |
+ // ------------------------------------------------------
+ //
+ // Reserved Opcode
+ // Appears to simply store the unsigned 16-bit sum of vector elements into low accumulator slice.
+ // Zeroes destination vector.
+
+ for (int i = 0; i < 8; i++)
+ {
+ vres[i] = m_v[VS1REG].w[i];
+ m_accum[i].w[SLICE_L] = 0;
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ default: unimplemented_opcode(op); break;
+ }
+}
+
+void rsp_device::handle_cop2(uint32_t op)
+{
+ switch ((op >> 21) & 0x1f)
+ {
+ case 0x00: /* MFC2 */
+ {
+ // 31 25 20 15 10 6 0
+ // ---------------------------------------------------
+ // | 010010 | 00000 | TTTTT | DDDDD | IIII | 0000000 |
+ // ---------------------------------------------------
+
+ int el = (op >> 7) & 0xf;
+ uint16_t b1 = VREG_B(RDREG, (el+0) & 0xf);
+ uint16_t b2 = VREG_B(RDREG, (el+1) & 0xf);
+ if (RTREG) m_r[RTREG] = (int32_t)(int16_t)((b1 << 8) | (b2));
+ break;
+ }
+
+ case 0x02: /* CFC2 */
+ {
+ // 31 25 20 15 10 0
+ // ------------------------------------------------
+ // | 010010 | 00010 | TTTTT | DDDDD | 00000000000 |
+ // ------------------------------------------------
+
+ if (RTREG)
+ {
+ switch (RDREG)
+ {
+ case 0:
+ m_r[RTREG] = (m_vzero << 8) | m_vcarry;
+ if (m_r[RTREG] & 0x8000) m_r[RTREG] |= 0xffff0000;
+ break;
+ case 1:
+ m_r[RTREG] = (m_vclip2 << 8) | m_vcompare;
+ if (m_r[RTREG] & 0x8000) m_r[RTREG] |= 0xffff0000;
+ break;
+ case 2:
+ // Anciliary clipping flags
+ m_r[RTREG] = m_vclip1;
+ break;
+ }
+ }
+ break;
+ }
+
+ case 0x04: /* MTC2 */
+ {
+ // 31 25 20 15 10 6 0
+ // ---------------------------------------------------
+ // | 010010 | 00100 | TTTTT | DDDDD | IIII | 0000000 |
+ // ---------------------------------------------------
+
+ int el = (op >> 7) & 0xf;
+ W_VREG_B(RDREG, (el+0) & 0xf, (m_r[RTREG] >> 8) & 0xff);
+ W_VREG_B(RDREG, (el+1) & 0xf, (m_r[RTREG] >> 0) & 0xff);
+ break;
+ }
+
+ case 0x06: /* CTC2 */
+ {
+ // 31 25 20 15 10 0
+ // ------------------------------------------------
+ // | 010010 | 00110 | TTTTT | DDDDD | 00000000000 |
+ // ------------------------------------------------
+
+ switch (RDREG)
+ {
+ case 0:
+ m_vcarry = (uint8_t)m_r[RTREG];
+ m_vzero = (uint8_t)(m_r[RTREG] >> 8);
+ break;
+
+ case 1:
+ m_vcompare = (uint8_t)m_r[RTREG];
+ m_vclip2 = (uint8_t)(m_r[RTREG] >> 8);
+ break;
+
+ case 2:
+ m_vclip1 = (uint8_t)m_r[RTREG];
+ break;
+ }
+ break;
+ }
+
+ case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
+ case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
+ handle_vector_ops(op);
+ break;
+
+ default:
+ unimplemented_opcode(op);
+ break;
+ }
+}
+
+void rsp_device::handle_lwc2(uint32_t op)
+{
+ int base = (op >> 21) & 0x1f;
+ int dest = (op >> 16) & 0x1f;
+ int index = (op >> 7) & 0xf;
+ int offset = util::sext(op & 0x7f, 7);
+
+ switch ((op >> 11) & 0x1f)
+ {
+ case 0x00: /* LBV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 110010 | BBBBB | TTTTT | 00000 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Load 1 byte to vector byte index
+
+ uint32_t ea = (base) ? m_r[base] + offset : offset;
+ VREG_B(dest, index) = read_dmem_byte(ea);
+ break;
+ }
+
+ case 0x01: /* LSV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 110010 | BBBBB | TTTTT | 00001 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Loads 2 bytes starting from vector byte index
+
+ uint32_t ea = (base) ? m_r[base] + (offset * 2) : (offset * 2);
+
+ for (int i = index; i < index + 2; i++)
+ {
+ VREG_B(dest, i) = read_dmem_byte(ea);
+ ea++;
+ }
+ break;
+ }
+
+ case 0x02: /* LLV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 110010 | BBBBB | TTTTT | 00010 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Loads 4 bytes starting from vector byte index
+
+ uint32_t ea = (base) ? m_r[base] + (offset * 4) : (offset * 4);
+
+ for (int i = index; i < index + 4; i++)
+ {
+ VREG_B(dest, i) = read_dmem_byte(ea);
+ ea++;
+ }
+ break;
+ }
+
+ case 0x03: /* LDV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 110010 | BBBBB | TTTTT | 00011 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Loads 8 bytes starting from vector byte index
+
+ uint32_t ea = (base) ? m_r[base] + (offset * 8) : (offset * 8);
+
+ for (int i = index; i < index + 8; i++)
+ {
+ VREG_B(dest, i) = read_dmem_byte(ea);
+ ea++;
+ }
+ break;
+ }
+
+ case 0x04: /* LQV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 110010 | BBBBB | TTTTT | 00100 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Loads up to 16 bytes starting from vector byte index
+
+ uint32_t ea = (base) ? m_r[base] + (offset * 16) : (offset * 16);
+
+ int end = index + (16 - (ea & 0xf));
+ if (end > 16) end = 16;
+
+ for (int i = index; i < end; i++)
+ {
+ VREG_B(dest, i) = read_dmem_byte(ea);
+ ea++;
+ }
+ break;
+ }
+
+ case 0x05: /* LRV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 110010 | BBBBB | TTTTT | 00101 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Stores up to 16 bytes starting from right side until 16-byte boundary
+
+ uint32_t ea = (base) ? m_r[base] + (offset * 16) : (offset * 16);
+
+ index = 16 - ((ea & 0xf) - index);
+ ea &= ~0xf;
+
+ for (int i = index; i < 16; i++)
+ {
+ VREG_B(dest, i) = read_dmem_byte(ea);
+ ea++;
+ }
+ break;
+ }
+
+ case 0x06: /* LPV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 110010 | BBBBB | TTTTT | 00110 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Loads a byte as the upper 8 bits of each element
+
+ uint32_t ea = (base) ? m_r[base] + (offset * 8) : (offset * 8);
+
+ for (int i = 0; i < 8; i++)
+ {
+ m_v[dest].w[i] = read_dmem_byte(ea + (((16-index) + i) & 0xf)) << 8;
+ }
+ break;
+ }
+
+ case 0x07: /* LUV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 110010 | BBBBB | TTTTT | 00111 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Loads a byte as the bits 14-7 of each element
+
+ uint32_t ea = (base) ? m_r[base] + (offset * 8) : (offset * 8);
+
+ for (int i = 0; i < 8; i++)
+ {
+ m_v[dest].w[i] = read_dmem_byte(ea + (((16-index) + i) & 0xf)) << 7;
+ }
+ break;
+ }
+
+ case 0x08: /* LHV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 110010 | BBBBB | TTTTT | 01000 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Loads a byte as the bits 14-7 of each element, with 2-byte stride
+
+ uint32_t ea = (base) ? m_r[base] + (offset * 16) : (offset * 16);
+
+ for (int i = 0; i < 8; i++)
+ {
+ m_v[dest].w[i] = read_dmem_byte(ea + (((16-index) + (i<<1)) & 0xf)) << 7;
+ }
+ break;
+ }
+
+ case 0x09: /* LFV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 110010 | BBBBB | TTTTT | 01001 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Loads a byte as the bits 14-7 of upper or lower quad, with 4-byte stride
+
+ uint32_t ea = (base) ? m_r[base] + (offset * 16) : (offset * 16);
+
+ // NOTE: Not sure what happens if 16-byte boundary is crossed
+
+ int end = (index >> 1) + 4;
+
+ for (int i = index >> 1; i < end; i++)
+ {
+ m_v[dest].w[i] = read_dmem_byte(ea) << 7;
+ ea += 4;
+ }
+ break;
+ }
+
+ case 0x0a: /* LWV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 110010 | BBBBB | TTTTT | 01010 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Intended instruction behavior:
+ // Loads the full 128-bit vector starting from vector byte index and wrapping to index 0
+ // after byte index 15
+ //
+ // Actual instruction behavior:
+ // Loads the full 128-bit vector starting from vector byte index 0.
+ //
+ // Hardware testing has proven that the vector index is ignored when executing LWV.
+ // By contrast, SWV will function as intended when provided an index.
+
+ uint32_t ea = (base) ? m_r[base] + (offset * 16) : (offset * 16);
+
+ for (int i = 0; i < 16; i++)
+ {
+ VREG_B(dest, i) = read_dmem_byte(ea);
+ ea++;
+ }
+ break;
+ }
+
+ case 0x0b: /* LTV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 110010 | BBBBB | TTTTT | 01011 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Loads one element to maximum of 8 vectors, while incrementing element index
+
+ // FIXME: has a small problem with odd indices
+
+ int32_t vs = (op >> 16) & 0x1f;
+ int32_t ve = vs + 8;
+ if (ve > 32)
+ ve = 32;
+
+ if (index & 1) fatalerror("RSP: LTV: index = %d\n", index);
+
+ uint32_t ea = (base) ? m_r[base] + (offset * 16) : (offset * 16);
+ ea = ((ea + 8) & ~0xf) + (index & 1);
+
+ for (int32_t i = vs; i < ve; i++)
+ {
+ int32_t element = ((8 - (index >> 1) + (i-vs)) << 1);
+ VREG_B(i, (element & 0xf)) = read_dmem_byte(ea);
+ VREG_B(i, ((element + 1) & 0xf)) = read_dmem_byte(ea + 1);
+
+ ea += 2;
+ }
+ break;
+ }
+
+ default:
+ {
+ unimplemented_opcode(op);
+ break;
+ }
+ }
+}
+
+
+/***************************************************************************
+ Vector Store Instructions
+***************************************************************************/
+
+void rsp_device::handle_swc2(uint32_t op)
+{
+ int base = (op >> 21) & 0x1f;
+ int dest = (op >> 16) & 0x1f;
+ int index = (op >> 7) & 0xf;
+ int offset = util::sext(op & 0x7f, 7);
+
+ switch ((op >> 11) & 0x1f)
+ {
+ case 0x00: /* SBV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 111010 | BBBBB | TTTTT | 00000 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Stores 1 byte from vector byte index
+
+ uint32_t ea = (base) ? m_r[base] + offset : offset;
+ write_dmem_byte(ea, VREG_B(dest, index));
+ break;
+ }
+
+ case 0x01: /* SSV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 111010 | BBBBB | TTTTT | 00001 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Stores 2 bytes starting from vector byte index
+
+ uint32_t ea = (base) ? m_r[base] + (offset * 2) : (offset * 2);
+
+ for (int i = index; i < index + 2; i++)
+ {
+ write_dmem_byte(ea, VREG_B(dest, i));
+ ea++;
+ }
+ break;
+ }
+
+ case 0x02: /* SLV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 111010 | BBBBB | TTTTT | 00010 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Stores 4 bytes starting from vector byte index
+
+ uint32_t ea = (base) ? m_r[base] + (offset * 4) : (offset * 4);
+
+ for (int i = index; i < index + 4; i++)
+ {
+ write_dmem_byte(ea, VREG_B(dest, i));
+ ea++;
+ }
+ break;
+ }
+
+ case 0x03: /* SDV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 111010 | BBBBB | TTTTT | 00011 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Stores 8 bytes starting from vector byte index
+
+ uint32_t ea = (base) ? m_r[base] + (offset * 8) : (offset * 8);
+
+ for (int i = index; i < index + 8; i++)
+ {
+ write_dmem_byte(ea, VREG_B(dest, i));
+ ea++;
+ }
+ break;
+ }
+
+ case 0x04: /* SQV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 111010 | BBBBB | TTTTT | 00100 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Stores up to 16 bytes starting from vector byte index until 16-byte boundary
+
+ uint32_t ea = (base) ? m_r[base] + (offset * 16) : (offset * 16);
+ int end = index + (16 - (ea & 0xf));
+
+ for (int i = index; i < end; i++)
+ {
+ write_dmem_byte(ea, VREG_B(dest, i & 0xf));
+ ea++;
+ }
+ break;
+ }
+
+ case 0x05: /* SRV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 111010 | BBBBB | TTTTT | 00101 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Stores up to 16 bytes starting from right side until 16-byte boundary
+
+ uint32_t ea = (base) ? m_r[base] + (offset * 16) : (offset * 16);
+
+ int end = index + (ea & 0xf);
+ int o = (16 - (ea & 0xf)) & 0xf;
+ ea &= ~0xf;
+
+ for (int i = index; i < end; i++)
+ {
+ write_dmem_byte(ea, VREG_B(dest, ((i + o) & 0xf)));
+ ea++;
+ }
+ break;
+ }
+
+ case 0x06: /* SPV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 111010 | BBBBB | TTTTT | 00110 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Stores upper 8 bits of each element
+
+ uint32_t ea = (base) ? m_r[base] + (offset * 8) : (offset * 8);
+
+ for (int i = index; i < index + 8; i++)
+ {
+ if ((i & 0xf) < 8)
+ {
+ write_dmem_byte(ea, VREG_B(dest, ((i & 0xf) << 1)));
+ }
+ else
+ {
+ write_dmem_byte(ea, m_v[dest].s[i & 0x7] >> 7);
+ }
+ ea++;
+ }
+ break;
+ }
+
+ case 0x07: /* SUV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 111010 | BBBBB | TTTTT | 00111 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Stores bits 14-7 of each element
+
+ uint32_t ea = (base) ? m_r[base] + (offset * 8) : (offset * 8);
+
+ for (int i = index; i < index + 8; i++)
+ {
+ if ((i & 0xf) < 8)
+ {
+ write_dmem_byte(ea, m_v[dest].s[i & 0x7] >> 7);
+ }
+ else
+ {
+ write_dmem_byte(ea, VREG_B(dest, ((i & 0x7) << 1)));
+ }
+ ea++;
+ }
+ break;
+ }
+
+ case 0x08: /* SHV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 111010 | BBBBB | TTTTT | 01000 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Stores bits 14-7 of each element, with 2-byte stride
+
+ uint32_t ea = (base) ? m_r[base] + (offset * 16) : (offset * 16);
+
+ for (int i = 0; i < 8; i++)
+ {
+ uint8_t d = ((VREG_B(dest, ((index + (i << 1) + 0) & 0xf))) << 1) |
+ ((VREG_B(dest, ((index + (i << 1) + 1) & 0xf))) >> 7);
+
+ write_dmem_byte(ea, d);
+ ea += 2;
+ }
+ break;
+ }
+
+ case 0x09: /* SFV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 111010 | BBBBB | TTTTT | 01001 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Stores bits 14-7 of upper or lower quad, with 4-byte stride
+
+ // FIXME: only works for index 0 and index 8
+
+ uint32_t ea = (base) ? m_r[base] + (offset * 16) : (offset * 16);
+
+ int eaoffset = ea & 0xf;
+ ea &= ~0xf;
+
+ int end = (index >> 1) + 4;
+
+ for (int i = index >> 1; i < end; i++)
+ {
+ write_dmem_byte(ea + (eaoffset & 0xf), m_v[dest].s[i] >> 7);
+ eaoffset += 4;
+ }
+ break;
+ }
+
+ case 0x0a: /* SWV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 111010 | BBBBB | TTTTT | 01010 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Stores the full 128-bit vector starting from vector byte index and wrapping to index 0
+ // after byte index 15
+
+ uint32_t ea = (base) ? m_r[base] + (offset * 16) : (offset * 16);
+
+ int eaoffset = ea & 0xf;
+ ea &= ~0xf;
+
+ for (int i = index; i < index + 16; i++)
+ {
+ write_dmem_byte(ea + (eaoffset & 0xf), VREG_B(dest, i & 0xf));
+ eaoffset++;
+ }
+ break;
+ }
+
+ case 0x0b: /* STV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 111010 | BBBBB | TTTTT | 01011 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Stores one element from maximum of 8 vectors, while incrementing element index
+
+ int32_t vs = (op >> 16) & 0x1f;
+ int32_t ve = vs + 8;
+ if (ve > 32)
+ ve = 32;
+
+ int32_t element = 8 - (index >> 1);
+
+ uint32_t ea = (base) ? m_r[base] + (offset * 16) : (offset * 16);
+
+ int32_t eaoffset = (ea & 0xf) + (element * 2);
+ ea &= ~0xf;
+
+ for (int32_t i = vs; i < ve; i++)
+ {
+ write_dmem_word(ea + (eaoffset & 0xf), m_v[i].w[element & 0x7]);
+ eaoffset += 2;
+ element++;
+ }
+ break;
+ }
+
+ default:
+ unimplemented_opcode(op);
+ break;
+ }
+}
+
+void rsp_device::update_scalar_op_deduction()
+{
+ /*if (m_paired_busy)
+ {
+ m_scalar_busy = false;
+ m_vector_busy = false;
+ m_paired_busy = false;
+ m_ideduct = 1;
+ }
+ else if (m_vector_busy)
+ {
+ m_scalar_busy = true;
+ m_paired_busy = true;
+ m_ideduct = 0;
+ }
+ else if (m_scalar_busy)
+ {
+ m_ideduct = 1;
+ }
+ else
+ {
+ m_scalar_busy = true;
+ m_ideduct = 0;
+ }*/
+}
+
+void rsp_device::update_vector_op_deduction()
+{
+ /*if (m_paired_busy)
+ {
+ m_scalar_busy = false;
+ m_vector_busy = false;
+ m_paired_busy = false;
+ m_ideduct = 1;
+ }
+ else if (m_scalar_busy)
+ {
+ m_vector_busy = true;
+ m_paired_busy = true;
+ m_ideduct = 0;
}
+ else if (m_vector_busy)
+ {
+ m_ideduct = 1;
+ }
+ else
+ {
+ m_vector_busy = true;
+ m_ideduct = 0;
+ }*/
+}
- while (m_rsp_state->icount > 0)
+void rsp_device::execute_run()
+{
+ if (m_sr & (RSP_STATUS_HALT | RSP_STATUS_BROKE))
{
- m_ppc = m_rsp_state->pc;
- debugger_instruction_hook(m_rsp_state->pc);
+ m_ideduct = 0;
+ m_scalar_busy = false;
+ m_vector_busy = false;
+ m_paired_busy = false;
+ m_icount = std::min(m_icount, 0);
+ }
- uint32_t op = ROPCODE(m_rsp_state->pc);
- if (m_nextpc != ~0)
+ while (m_icount > 0)
+ {
+ m_ppc = m_pc;
+ debugger_instruction_hook(m_pc);
+
+ uint32_t op = ROPCODE(m_pc);
+ if (m_nextpc != 0xffff)
{
- m_rsp_state->pc = m_nextpc;
- m_nextpc = ~0;
+ m_pc = m_nextpc;
+ m_nextpc = 0xffff;
}
else
{
- m_rsp_state->pc += 4;
+ m_pc += 4;
}
switch (op >> 26)
{
case 0x00: /* SPECIAL */
{
+ update_scalar_op_deduction();
switch (op & 0x3f)
{
- case 0x00: /* SLL */ if (RDREG) RDVAL = (uint32_t)RTVAL << SHIFT; break;
- case 0x02: /* SRL */ if (RDREG) RDVAL = (uint32_t)RTVAL >> SHIFT; break;
- case 0x03: /* SRA */ if (RDREG) RDVAL = (int32_t)RTVAL >> SHIFT; break;
- case 0x04: /* SLLV */ if (RDREG) RDVAL = (uint32_t)RTVAL << (RSVAL & 0x1f); break;
- case 0x06: /* SRLV */ if (RDREG) RDVAL = (uint32_t)RTVAL >> (RSVAL & 0x1f); break;
- case 0x07: /* SRAV */ if (RDREG) RDVAL = (int32_t)RTVAL >> (RSVAL & 0x1f); break;
- case 0x08: /* JR */ JUMP_PC(RSVAL); break;
- case 0x09: /* JALR */ JUMP_PC_L(RSVAL, RDREG); break;
+ case 0x00: /* SLL */ if (RDREG) m_r[RDREG] = m_r[RTREG] << SHIFT; break;
+ case 0x02: /* SRL */ if (RDREG) m_r[RDREG] = m_r[RTREG] >> SHIFT; break;
+ case 0x03: /* SRA */ if (RDREG) m_r[RDREG] = (int32_t)m_r[RTREG] >> SHIFT; break;
+ case 0x04: /* SLLV */ if (RDREG) m_r[RDREG] = m_r[RTREG] << (m_r[RSREG] & 0x1f); break;
+ case 0x06: /* SRLV */ if (RDREG) m_r[RDREG] = m_r[RTREG] >> (m_r[RSREG] & 0x1f); break;
+ case 0x07: /* SRAV */ if (RDREG) m_r[RDREG] = (int32_t)m_r[RTREG] >> (m_r[RSREG] & 0x1f); break;
+ case 0x08: /* JR */ JUMP_PC(m_r[RSREG]); break;
+ case 0x09: /* JALR */ JUMP_PC_L(m_r[RSREG], RDREG); break;
case 0x0d: /* BREAK */
{
+ m_ideduct = 1;
+ m_scalar_busy = false;
+ m_vector_busy = false;
+ m_paired_busy = false;
m_sp_set_status_func(0, 0x3, 0xffffffff);
- m_rsp_state->icount = std::min(m_rsp_state->icount, 1);
+ m_icount = std::min(m_icount, 1);
break;
}
- case 0x20: /* ADD */ if (RDREG) RDVAL = (int32_t)(RSVAL + RTVAL); break;
- case 0x21: /* ADDU */ if (RDREG) RDVAL = (int32_t)(RSVAL + RTVAL); break;
- case 0x22: /* SUB */ if (RDREG) RDVAL = (int32_t)(RSVAL - RTVAL); break;
- case 0x23: /* SUBU */ if (RDREG) RDVAL = (int32_t)(RSVAL - RTVAL); break;
- case 0x24: /* AND */ if (RDREG) RDVAL = RSVAL & RTVAL; break;
- case 0x25: /* OR */ if (RDREG) RDVAL = RSVAL | RTVAL; break;
- case 0x26: /* XOR */ if (RDREG) RDVAL = RSVAL ^ RTVAL; break;
- case 0x27: /* NOR */ if (RDREG) RDVAL = ~(RSVAL | RTVAL); break;
- case 0x2a: /* SLT */ if (RDREG) RDVAL = (int32_t)RSVAL < (int32_t)RTVAL; break;
- case 0x2b: /* SLTU */ if (RDREG) RDVAL = (uint32_t)RSVAL < (uint32_t)RTVAL; break;
+ case 0x20: /* ADD */ if (RDREG) m_r[RDREG] = (int32_t)(m_r[RSREG] + m_r[RTREG]); break;
+ case 0x21: /* ADDU */ if (RDREG) m_r[RDREG] = (int32_t)(m_r[RSREG] + m_r[RTREG]); break;
+ case 0x22: /* SUB */ if (RDREG) m_r[RDREG] = (int32_t)(m_r[RSREG] - m_r[RTREG]); break;
+ case 0x23: /* SUBU */ if (RDREG) m_r[RDREG] = (int32_t)(m_r[RSREG] - m_r[RTREG]); break;
+ case 0x24: /* AND */ if (RDREG) m_r[RDREG] = m_r[RSREG] & m_r[RTREG]; break;
+ case 0x25: /* OR */ if (RDREG) m_r[RDREG] = m_r[RSREG] | m_r[RTREG]; break;
+ case 0x26: /* XOR */ if (RDREG) m_r[RDREG] = m_r[RSREG] ^ m_r[RTREG]; break;
+ case 0x27: /* NOR */ if (RDREG) m_r[RDREG] = ~(m_r[RSREG] | m_r[RTREG]); break;
+ case 0x2a: /* SLT */ if (RDREG) m_r[RDREG] = (int32_t)m_r[RSREG] < (int32_t)m_r[RTREG]; break;
+ case 0x2b: /* SLTU */ if (RDREG) m_r[RDREG] = m_r[RSREG] < m_r[RTREG]; break;
default: unimplemented_opcode(op); break;
}
break;
@@ -680,38 +2905,40 @@ void rsp_device::execute_run()
case 0x01: /* REGIMM */
{
+ update_scalar_op_deduction();
switch (RTREG)
{
- case 0x00: /* BLTZ */ if ((int32_t)(RSVAL) < 0) JUMP_REL(SIMM16); break;
- case 0x01: /* BGEZ */ if ((int32_t)(RSVAL) >= 0) JUMP_REL(SIMM16); break;
- case 0x10: /* BLTZAL */ if ((int32_t)(RSVAL) < 0) JUMP_REL_L(SIMM16, 31); break;
- case 0x11: /* BGEZAL */ if ((int32_t)(RSVAL) >= 0) JUMP_REL_L(SIMM16, 31); break;
+ case 0x00: /* BLTZ */ if ((int32_t)m_r[RSREG] < 0) JUMP_REL(SIMM16); break;
+ case 0x01: /* BGEZ */ if ((int32_t)m_r[RSREG] >= 0) JUMP_REL(SIMM16); break;
+ case 0x10: /* BLTZAL */ if ((int32_t)m_r[RSREG] < 0) JUMP_REL_L(SIMM16, 31); break;
+ case 0x11: /* BGEZAL */ if ((int32_t)m_r[RSREG] >= 0) JUMP_REL_L(SIMM16, 31); break;
default: unimplemented_opcode(op); break;
}
break;
}
- case 0x02: /* J */ JUMP_ABS(UIMM26); break;
- case 0x03: /* JAL */ JUMP_ABS_L(UIMM26, 31); break;
- case 0x04: /* BEQ */ if (RSVAL == RTVAL) JUMP_REL(SIMM16); break;
- case 0x05: /* BNE */ if (RSVAL != RTVAL) JUMP_REL(SIMM16); break;
- case 0x06: /* BLEZ */ if ((int32_t)RSVAL <= 0) JUMP_REL(SIMM16); break;
- case 0x07: /* BGTZ */ if ((int32_t)RSVAL > 0) JUMP_REL(SIMM16); break;
- case 0x08: /* ADDI */ if (RTREG) RTVAL = (int32_t)(RSVAL + SIMM16); break;
- case 0x09: /* ADDIU */ if (RTREG) RTVAL = (int32_t)(RSVAL + SIMM16); break;
- case 0x0a: /* SLTI */ if (RTREG) RTVAL = (int32_t)(RSVAL) < ((int32_t)SIMM16); break;
- case 0x0b: /* SLTIU */ if (RTREG) RTVAL = (uint32_t)(RSVAL) < (uint32_t)((int32_t)SIMM16); break;
- case 0x0c: /* ANDI */ if (RTREG) RTVAL = RSVAL & UIMM16; break;
- case 0x0d: /* ORI */ if (RTREG) RTVAL = RSVAL | UIMM16; break;
- case 0x0e: /* XORI */ if (RTREG) RTVAL = RSVAL ^ UIMM16; break;
- case 0x0f: /* LUI */ if (RTREG) RTVAL = UIMM16 << 16; break;
+ case 0x02: /* J */ update_scalar_op_deduction(); JUMP_ABS(UIMM26); break;
+ case 0x03: /* JAL */ update_scalar_op_deduction(); JUMP_ABS_L(UIMM26, 31); break;
+ case 0x04: /* BEQ */ update_scalar_op_deduction(); if (m_r[RSREG] == m_r[RTREG]) JUMP_REL(SIMM16); break;
+ case 0x05: /* BNE */ update_scalar_op_deduction(); if (m_r[RSREG] != m_r[RTREG]) JUMP_REL(SIMM16); break;
+ case 0x06: /* BLEZ */ update_scalar_op_deduction(); if ((int32_t)m_r[RSREG] <= 0) JUMP_REL(SIMM16); break;
+ case 0x07: /* BGTZ */ update_scalar_op_deduction(); if ((int32_t)m_r[RSREG] > 0) JUMP_REL(SIMM16); break;
+ case 0x08: /* ADDI */ update_scalar_op_deduction(); if (RTREG) m_r[RTREG] = (int32_t)m_r[RSREG] + SIMM16; break;
+ case 0x09: /* ADDIU */ update_scalar_op_deduction(); if (RTREG) m_r[RTREG] = (int32_t)m_r[RSREG] + SIMM16; break;
+ case 0x0a: /* SLTI */ update_scalar_op_deduction(); if (RTREG) m_r[RTREG] = (int32_t)m_r[RSREG] < (int32_t)SIMM16; break;
+ case 0x0b: /* SLTIU */ update_scalar_op_deduction(); if (RTREG) m_r[RTREG] = m_r[RSREG] < UIMM16; break;
+ case 0x0c: /* ANDI */ update_scalar_op_deduction(); if (RTREG) m_r[RTREG] = m_r[RSREG] & UIMM16; break;
+ case 0x0d: /* ORI */ update_scalar_op_deduction(); if (RTREG) m_r[RTREG] = m_r[RSREG] | UIMM16; break;
+ case 0x0e: /* XORI */ update_scalar_op_deduction(); if (RTREG) m_r[RTREG] = m_r[RSREG] ^ UIMM16; break;
+ case 0x0f: /* LUI */ update_scalar_op_deduction(); if (RTREG) m_r[RTREG] = UIMM16 << 16; break;
case 0x10: /* COP0 */
{
+ update_scalar_op_deduction();
switch ((op >> 21) & 0x1f)
{
- case 0x00: /* MFC0 */ if (RTREG) RTVAL = get_cop0_reg(RDREG); break;
- case 0x04: /* MTC0 */ set_cop0_reg(RDREG, RTVAL); break;
+ case 0x00: /* MFC0 */ if (RTREG) m_r[RTREG] = get_cop0_reg(RDREG); break;
+ case 0x04: /* MTC0 */ set_cop0_reg(RDREG, m_r[RTREG]); break;
default: unimplemented_opcode(op); break;
}
break;
@@ -719,20 +2946,21 @@ void rsp_device::execute_run()
case 0x12: /* COP2 */
{
- m_cop2->handle_cop2(op);
+ update_vector_op_deduction();
+ handle_cop2(op);
break;
}
- case 0x20: /* LB */ if (RTREG) RTVAL = (int32_t)(int8_t)READ8(RSVAL + SIMM16); break;
- case 0x21: /* LH */ if (RTREG) RTVAL = (int32_t)(int16_t)READ16(RSVAL + SIMM16); break;
- case 0x23: /* LW */ if (RTREG) RTVAL = READ32(RSVAL + SIMM16); break;
- case 0x24: /* LBU */ if (RTREG) RTVAL = (uint8_t)READ8(RSVAL + SIMM16); break;
- case 0x25: /* LHU */ if (RTREG) RTVAL = (uint16_t)READ16(RSVAL + SIMM16); break;
- case 0x28: /* SB */ WRITE8(RSVAL + SIMM16, RTVAL); break;
- case 0x29: /* SH */ WRITE16(RSVAL + SIMM16, RTVAL); break;
- case 0x2b: /* SW */ WRITE32(RSVAL + SIMM16, RTVAL); break;
- case 0x32: /* LWC2 */ m_cop2->handle_lwc2(op); break;
- case 0x3a: /* SWC2 */ m_cop2->handle_swc2(op); break;
+ case 0x20: /* LB */ update_scalar_op_deduction(); if (RTREG) m_r[RTREG] = (int32_t)(int8_t)read_dmem_byte(m_r[RSREG] + SIMM16); break;
+ case 0x21: /* LH */ update_scalar_op_deduction(); if (RTREG) m_r[RTREG] = (int32_t)(int16_t)read_dmem_word(m_r[RSREG] + SIMM16); break;
+ case 0x23: /* LW */ update_scalar_op_deduction(); if (RTREG) m_r[RTREG] = read_dmem_dword(m_r[RSREG] + SIMM16); break;
+ case 0x24: /* LBU */ update_scalar_op_deduction(); if (RTREG) m_r[RTREG] = read_dmem_byte(m_r[RSREG] + SIMM16); break;
+ case 0x25: /* LHU */ update_scalar_op_deduction(); if (RTREG) m_r[RTREG] = read_dmem_word(m_r[RSREG] + SIMM16); break;
+ case 0x28: /* SB */ update_scalar_op_deduction(); write_dmem_byte(m_r[RSREG] + SIMM16, m_r[RTREG]); break;
+ case 0x29: /* SH */ update_scalar_op_deduction(); write_dmem_word(m_r[RSREG] + SIMM16, m_r[RTREG]); break;
+ case 0x2b: /* SW */ update_scalar_op_deduction(); write_dmem_dword(m_r[RSREG] + SIMM16, m_r[RTREG]); break;
+ case 0x32: /* LWC2 */ update_scalar_op_deduction(); handle_lwc2(op); break;
+ case 0x3a: /* SWC2 */ update_scalar_op_deduction(); handle_swc2(op); break;
default:
{
@@ -743,8 +2971,8 @@ void rsp_device::execute_run()
if (LOG_INSTRUCTION_EXECUTION)
{
- int i, l;
static uint32_t prev_regs[32];
+ static VECTOR_REG prev_vecs[32];
rsp_disassembler rspd;
std::ostringstream string;
@@ -752,10 +2980,10 @@ void rsp_device::execute_run()
fprintf(m_exec_output, "%08X: %s", m_ppc, string.str().c_str());
- l = string.str().size();
+ int l = string.str().size();
if (l < 36)
{
- for (i=l; i < 36; i++)
+ for (int i = l; i < 36; i++)
{
fprintf(m_exec_output, " ");
}
@@ -763,26 +2991,36 @@ void rsp_device::execute_run()
fprintf(m_exec_output, "| ");
- for (i=0; i < 32; i++)
+ for (int i = 0; i < 32; i++)
{
- if (m_rsp_state->r[i] != prev_regs[i])
+ if (m_r[i] != prev_regs[i])
{
- fprintf(m_exec_output, "R%d: %08X ", i, m_rsp_state->r[i]);
+ fprintf(m_exec_output, "R%d: %08X ", i, m_r[i]);
}
- prev_regs[i] = m_rsp_state->r[i];
+ prev_regs[i] = m_r[i];
}
- m_cop2->log_instruction_execution();
+ for (int i = 0; i < 32; i++)
+ {
+ if (m_v[i].d[0] != prev_vecs[i].d[0] || m_v[i].d[1] != prev_vecs[i].d[1])
+ {
+ fprintf(m_exec_output, "V%d: %04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X ", i,
+ m_v[i].w[0], m_v[i].w[1], m_v[i].w[2], m_v[i].w[3], m_v[i].w[4], m_v[i].w[5], m_v[i].w[6], m_v[i].w[7]);
+ }
+ prev_vecs[i].d[0] = m_v[i].d[0];
+ prev_vecs[i].d[1] = m_v[i].d[1];
+ }
fprintf(m_exec_output, "\n");
}
- --m_rsp_state->icount;
+ //m_icount -= m_ideduct;
+ --m_icount;
- if( m_sr & RSP_STATUS_SSTEP )
+ if (m_sr & RSP_STATUS_SSTEP)
{
- if( m_step_count )
+ if (m_step_count)
{
m_step_count--;
}
@@ -792,14 +3030,13 @@ void rsp_device::execute_run()
}
}
- if( m_sr & ( RSP_STATUS_HALT | RSP_STATUS_BROKE ) )
+ if (m_sr & (RSP_STATUS_HALT | RSP_STATUS_BROKE))
{
- m_rsp_state->icount = std::min(m_rsp_state->icount, 0);
+ m_ideduct = 0;
+ m_scalar_busy = false;
+ m_vector_busy = false;
+ m_paired_busy = false;
+ m_icount = std::min(m_icount, 0);
}
- /*m_cop2->dump(op);
- if (((op >> 26) & 0x3f) == 0x3a)
- {
- m_cop2->dump_dmem();
- }*/
}
}