Files
simple64/parallel-rsp/rsp/vfunctions.cpp
T
2024-03-22 11:41:49 -06:00

846 lines
21 KiB
C++

//
// rsp/vfunctions.c: RSP vector execution functions.
//
// CEN64: Cycle-Accurate Nintendo 64 Emulator.
// Copyright (C) 2015, Tyler J. Stachecki.
//
// This file is subject to the terms and conditions defined in
// 'LICENSE', which is part of this source code package.
//
#include "../state.hpp"
#include "../rsp_op.hpp"
#include "rsp_impl.h"
#include <stdio.h>
#define LOAD_VS() rsp_vect_load_unshuffled_operand(rsp->cp2.regs[vs].e)
#define LOAD_VT() rsp_vect_load_and_shuffle_operand(rsp->cp2.regs[vt].e, e)
#define STORE_RESULT() rsp_vect_write_operand(rsp->cp2.regs[vd].e, result)
#ifdef TRACE_COP2
#define TRACE_VU(op) printf(#op " v%u, v%u, v%u[%u]\n", vd, vs, vt, e)
#else
#define TRACE_VU(op) ((void)0)
#endif
extern "C"
{
static inline int32_t clamp16s(int32_t x)
{
if (x > 0x7fff) return 0x7fff;
if (x < -0x8000) return -0x8000;
return x;
}
//
// VABS
//
void RSP_VABS(RSP::CPUState *rsp, unsigned vd, unsigned vs, unsigned vt, unsigned e)
{
TRACE_VU(VABS);
uint16_t *acc = rsp->cp2.acc.e;
rsp_vect_t acc_lo;
rsp_vect_t result = rsp_vabs(LOAD_VS(), LOAD_VT(), &acc_lo);
write_acc_lo(acc, acc_lo);
rsp_vect_write_operand(rsp->cp2.regs[vd].e, result);
}
//
// VADD
//
void RSP_VADD(RSP::CPUState *rsp, unsigned vd, unsigned vs, unsigned vt, unsigned e)
{
TRACE_VU(VADD);
uint16_t *acc = rsp->cp2.acc.e;
rsp_vect_t carry, acc_lo;
carry = read_vco_lo(rsp->cp2.flags[RSP::RSP_VCO].e);
rsp_vect_t result = rsp_vadd(LOAD_VS(), LOAD_VT(), carry, &acc_lo);
write_vco_hi(rsp->cp2.flags[RSP::RSP_VCO].e, rsp_vzero());
write_vco_lo(rsp->cp2.flags[RSP::RSP_VCO].e, rsp_vzero());
write_acc_lo(acc, acc_lo);
STORE_RESULT();
}
//
// VADDC
//
void RSP_VADDC(RSP::CPUState *rsp, unsigned vd, unsigned vs, unsigned vt, unsigned e)
{
TRACE_VU(VADDC);
uint16_t *acc = rsp->cp2.acc.e;
rsp_vect_t sn;
rsp_vect_t result = rsp_vaddc(LOAD_VS(), LOAD_VT(), rsp_vzero(), &sn);
write_vco_hi(rsp->cp2.flags[RSP::RSP_VCO].e, rsp_vzero()); // TODO: Confirm.
write_vco_lo(rsp->cp2.flags[RSP::RSP_VCO].e, sn);
write_acc_lo(acc, result);
STORE_RESULT();
}
//
// VAND
// VNAND
//
void RSP_VAND(RSP::CPUState *rsp, unsigned vd, unsigned vs, unsigned vt, unsigned e)
{
TRACE_VU(VAND);
uint16_t *acc = rsp->cp2.acc.e;
rsp_vect_t result = rsp_vand(LOAD_VS(), LOAD_VT());
write_acc_lo(acc, result);
STORE_RESULT();
}
void RSP_VNAND(RSP::CPUState *rsp, unsigned vd, unsigned vs, unsigned vt, unsigned e)
{
TRACE_VU(VNAND);
uint16_t *acc = rsp->cp2.acc.e;
rsp_vect_t result = rsp_vnand(LOAD_VS(), LOAD_VT());
write_acc_lo(acc, result);
STORE_RESULT();
}
//
// VCH
//
void RSP_VCH(RSP::CPUState *rsp, unsigned vd, unsigned vs, unsigned vt, unsigned e)
{
TRACE_VU(VCH);
uint16_t *acc = rsp->cp2.acc.e;
rsp_vect_t ge, le, sign, eq, vce;
rsp_vect_t result = rsp_vch(LOAD_VS(), LOAD_VT(), rsp_vzero(), &ge, &le, &eq, &sign, &vce);
write_vcc_hi(rsp->cp2.flags[RSP::RSP_VCC].e, ge);
write_vcc_lo(rsp->cp2.flags[RSP::RSP_VCC].e, le);
write_vco_hi(rsp->cp2.flags[RSP::RSP_VCO].e, eq);
write_vco_lo(rsp->cp2.flags[RSP::RSP_VCO].e, sign);
write_vce(rsp->cp2.flags[RSP::RSP_VCE].e, vce);
write_acc_lo(acc, result);
STORE_RESULT();
}
//
// VCL
//
void RSP_VCL(RSP::CPUState *rsp, unsigned vd, unsigned vs, unsigned vt, unsigned e)
{
TRACE_VU(VCL);
uint16_t *acc = rsp->cp2.acc.e;
rsp_vect_t ge, le, eq, sign, vce;
ge = read_vcc_hi(rsp->cp2.flags[RSP::RSP_VCC].e);
le = read_vcc_lo(rsp->cp2.flags[RSP::RSP_VCC].e);
eq = read_vco_hi(rsp->cp2.flags[RSP::RSP_VCO].e);
sign = read_vco_lo(rsp->cp2.flags[RSP::RSP_VCO].e);
vce = read_vce(rsp->cp2.flags[RSP::RSP_VCE].e);
rsp_vect_t result = rsp_vcl(LOAD_VS(), LOAD_VT(), rsp_vzero(), &ge, &le, eq, sign, vce);
write_vcc_hi(rsp->cp2.flags[RSP::RSP_VCC].e, ge);
write_vcc_lo(rsp->cp2.flags[RSP::RSP_VCC].e, le);
write_vco_hi(rsp->cp2.flags[RSP::RSP_VCO].e, rsp_vzero());
write_vco_lo(rsp->cp2.flags[RSP::RSP_VCO].e, rsp_vzero());
write_vce(rsp->cp2.flags[RSP::RSP_VCE].e, rsp_vzero());
write_acc_lo(acc, result);
STORE_RESULT();
}
//
// VCR
//
void RSP_VCR(RSP::CPUState *rsp, unsigned vd, unsigned vs, unsigned vt, unsigned e)
{
TRACE_VU(VCR);
uint16_t *acc = rsp->cp2.acc.e;
rsp_vect_t ge, le;
rsp_vect_t result = rsp_vcr(LOAD_VS(), LOAD_VT(), rsp_vzero(), &ge, &le);
#ifdef INTENSE_DEBUG
for (unsigned i = 0; i < 8; i++)
fprintf(stderr, "VD[%d] = %d\n", i, reinterpret_cast<int16_t *>(&result)[i]);
#endif
write_vcc_hi(rsp->cp2.flags[RSP::RSP_VCC].e, ge);
write_vcc_lo(rsp->cp2.flags[RSP::RSP_VCC].e, le);
write_vco_hi(rsp->cp2.flags[RSP::RSP_VCO].e, rsp_vzero());
write_vco_lo(rsp->cp2.flags[RSP::RSP_VCO].e, rsp_vzero());
write_vce(rsp->cp2.flags[RSP::RSP_VCE].e, rsp_vzero());
write_acc_lo(acc, result);
STORE_RESULT();
}
//
// VEQ
// VGE
// VLT
// VNE
//
void RSP_VEQ(RSP::CPUState *rsp, unsigned vd, unsigned vs, unsigned vt, unsigned e)
{
TRACE_VU(VEQ);
uint16_t *acc = rsp->cp2.acc.e;
rsp_vect_t le, eq, sign;
eq = read_vco_hi(rsp->cp2.flags[RSP::RSP_VCO].e);
sign = read_vco_lo(rsp->cp2.flags[RSP::RSP_VCO].e);
rsp_vect_t result = rsp_veq(LOAD_VS(), LOAD_VT(), rsp_vzero(), &le, eq, sign);
write_vcc_hi(rsp->cp2.flags[RSP::RSP_VCC].e, rsp_vzero());
write_vcc_lo(rsp->cp2.flags[RSP::RSP_VCC].e, le);
write_vco_hi(rsp->cp2.flags[RSP::RSP_VCO].e, rsp_vzero());
write_vco_lo(rsp->cp2.flags[RSP::RSP_VCO].e, rsp_vzero());
write_acc_lo(acc, result);
STORE_RESULT();
}
void RSP_VGE(RSP::CPUState *rsp, unsigned vd, unsigned vs, unsigned vt, unsigned e)
{
TRACE_VU(VGE);
uint16_t *acc = rsp->cp2.acc.e;
rsp_vect_t le, eq, sign;
eq = read_vco_hi(rsp->cp2.flags[RSP::RSP_VCO].e);
sign = read_vco_lo(rsp->cp2.flags[RSP::RSP_VCO].e);
rsp_vect_t result = rsp_vge(LOAD_VS(), LOAD_VT(), rsp_vzero(), &le, eq, sign);
write_vcc_hi(rsp->cp2.flags[RSP::RSP_VCC].e, rsp_vzero());
write_vcc_lo(rsp->cp2.flags[RSP::RSP_VCC].e, le);
write_vco_hi(rsp->cp2.flags[RSP::RSP_VCO].e, rsp_vzero());
write_vco_lo(rsp->cp2.flags[RSP::RSP_VCO].e, rsp_vzero());
write_acc_lo(acc, result);
STORE_RESULT();
}
void RSP_VLT(RSP::CPUState *rsp, unsigned vd, unsigned vs, unsigned vt, unsigned e)
{
TRACE_VU(VLT);
uint16_t *acc = rsp->cp2.acc.e;
rsp_vect_t le, eq, sign;
eq = read_vco_hi(rsp->cp2.flags[RSP::RSP_VCO].e);
sign = read_vco_lo(rsp->cp2.flags[RSP::RSP_VCO].e);
rsp_vect_t result = rsp_vlt(LOAD_VS(), LOAD_VT(), rsp_vzero(), &le, eq, sign);
write_vcc_hi(rsp->cp2.flags[RSP::RSP_VCC].e, rsp_vzero());
write_vcc_lo(rsp->cp2.flags[RSP::RSP_VCC].e, le);
write_vco_hi(rsp->cp2.flags[RSP::RSP_VCO].e, rsp_vzero());
write_vco_lo(rsp->cp2.flags[RSP::RSP_VCO].e, rsp_vzero());
write_acc_lo(acc, result);
STORE_RESULT();
}
void RSP_VNE(RSP::CPUState *rsp, unsigned vd, unsigned vs, unsigned vt, unsigned e)
{
TRACE_VU(VNE);
uint16_t *acc = rsp->cp2.acc.e;
rsp_vect_t le, eq, sign;
eq = read_vco_hi(rsp->cp2.flags[RSP::RSP_VCO].e);
sign = read_vco_lo(rsp->cp2.flags[RSP::RSP_VCO].e);
rsp_vect_t result = rsp_vne(LOAD_VS(), LOAD_VT(), rsp_vzero(), &le, eq, sign);
#ifdef INTENSE_DEBUG
for (unsigned i = 0; i < 8; i++)
fprintf(stderr, "VD[%d] = %d\n", i, reinterpret_cast<int16_t *>(&result)[i]);
#endif
write_vcc_hi(rsp->cp2.flags[RSP::RSP_VCC].e, rsp_vzero());
write_vcc_lo(rsp->cp2.flags[RSP::RSP_VCC].e, le);
write_vco_hi(rsp->cp2.flags[RSP::RSP_VCO].e, rsp_vzero());
write_vco_lo(rsp->cp2.flags[RSP::RSP_VCO].e, rsp_vzero());
write_acc_lo(acc, result);
STORE_RESULT();
}
//
// VINVALID
//
void RSP_VINVALID(RSP::CPUState *, unsigned, unsigned, unsigned, unsigned)
{
fprintf(stderr, "Unimplemented ...\n");
}
//
// VMACF
// VMACU
//
void RSP_VMACF(RSP::CPUState *rsp, unsigned vd, unsigned vs, unsigned vt, unsigned e)
{
TRACE_VU(VMACF);
uint16_t *acc = rsp->cp2.acc.e;
rsp_vect_t acc_lo, acc_md, acc_hi, result;
acc_lo = read_acc_lo(acc);
acc_md = read_acc_md(acc);
acc_hi = read_acc_hi(acc);
result = rsp_vmacf_vmacu<false>(LOAD_VS(), LOAD_VT(), rsp_vzero(), &acc_lo, &acc_md, &acc_hi);
write_acc_lo(acc, acc_lo);
write_acc_md(acc, acc_md);
write_acc_hi(acc, acc_hi);
STORE_RESULT();
}
void RSP_VMACU(RSP::CPUState *rsp, unsigned vd, unsigned vs, unsigned vt, unsigned e)
{
TRACE_VU(VMACU);
uint16_t *acc = rsp->cp2.acc.e;
rsp_vect_t acc_lo, acc_md, acc_hi, result;
acc_lo = read_acc_lo(acc);
acc_md = read_acc_md(acc);
acc_hi = read_acc_hi(acc);
result = rsp_vmacf_vmacu<true>(LOAD_VS(), LOAD_VT(), rsp_vzero(), &acc_lo, &acc_md, &acc_hi);
write_acc_lo(acc, acc_lo);
write_acc_md(acc, acc_md);
write_acc_hi(acc, acc_hi);
STORE_RESULT();
}
void RSP_VMACQ(RSP::CPUState *rsp, unsigned vd, unsigned, unsigned, unsigned)
{
TRACE_VU(VMACQ);
uint16_t *acc = rsp->cp2.acc.e;
for (unsigned i = 0; i < 8; i++)
{
int32_t prod = (int16_t)acc[i] << 16;
prod |= acc[8+i];
if (prod < 0 && !(prod & 1 << 5))
prod += 32;
else if (prod >= 32 && !(prod & 1 << 5))
prod -= 32;
acc[i] = prod >> 16;
acc[8+i] = prod & 0xffffu;
rsp->cp2.regs[vd].e[i] = clamp16s(prod >> 1) & ~15;
}
}
//
// VMADH
// VMUDH
//
void RSP_VMADH(RSP::CPUState *rsp, unsigned vd, unsigned vs, unsigned vt, unsigned e)
{
TRACE_VU(VMADH);
uint16_t *acc = rsp->cp2.acc.e;
rsp_vect_t acc_lo, acc_md, acc_hi, result;
acc_lo = read_acc_lo(acc);
acc_md = read_acc_md(acc);
acc_hi = read_acc_hi(acc);
result = rsp_vmadh_vmudh<true>(LOAD_VS(), LOAD_VT(), rsp_vzero(), &acc_lo, &acc_md, &acc_hi);
write_acc_lo(acc, acc_lo);
write_acc_md(acc, acc_md);
write_acc_hi(acc, acc_hi);
STORE_RESULT();
}
void RSP_VMUDH(RSP::CPUState *rsp, unsigned vd, unsigned vs, unsigned vt, unsigned e)
{
TRACE_VU(VMUDH);
uint16_t *acc = rsp->cp2.acc.e;
rsp_vect_t acc_lo, acc_md, acc_hi, result;
acc_lo = read_acc_lo(acc);
acc_md = read_acc_md(acc);
acc_hi = read_acc_hi(acc);
result = rsp_vmadh_vmudh<false>(LOAD_VS(), LOAD_VT(), rsp_vzero(), &acc_lo, &acc_md, &acc_hi);
write_acc_lo(acc, acc_lo);
write_acc_md(acc, acc_md);
write_acc_hi(acc, acc_hi);
STORE_RESULT();
}
//
// VMADL
// VMUDL
//
void RSP_VMADL(RSP::CPUState *rsp, unsigned vd, unsigned vs, unsigned vt, unsigned e)
{
TRACE_VU(VMADL);
uint16_t *acc = rsp->cp2.acc.e;
rsp_vect_t acc_lo, acc_md, acc_hi, result;
acc_lo = read_acc_lo(acc);
acc_md = read_acc_md(acc);
acc_hi = read_acc_hi(acc);
result = rsp_vmadl_vmudl<true>(LOAD_VS(), LOAD_VT(), rsp_vzero(), &acc_lo, &acc_md, &acc_hi);
write_acc_lo(acc, acc_lo);
write_acc_md(acc, acc_md);
write_acc_hi(acc, acc_hi);
STORE_RESULT();
}
void RSP_VMUDL(RSP::CPUState *rsp, unsigned vd, unsigned vs, unsigned vt, unsigned e)
{
TRACE_VU(VMUDL);
uint16_t *acc = rsp->cp2.acc.e;
rsp_vect_t acc_lo, acc_md, acc_hi, result;
acc_lo = read_acc_lo(acc);
acc_md = read_acc_md(acc);
acc_hi = read_acc_hi(acc);
result = rsp_vmadl_vmudl<false>(LOAD_VS(), LOAD_VT(), rsp_vzero(), &acc_lo, &acc_md, &acc_hi);
write_acc_lo(acc, acc_lo);
write_acc_md(acc, acc_md);
write_acc_hi(acc, acc_hi);
STORE_RESULT();
}
//
// VMADM
// VMUDM
//
void RSP_VMADM(RSP::CPUState *rsp, unsigned vd, unsigned vs, unsigned vt, unsigned e)
{
TRACE_VU(VMADM);
uint16_t *acc = rsp->cp2.acc.e;
rsp_vect_t acc_lo, acc_md, acc_hi, result;
acc_lo = read_acc_lo(acc);
acc_md = read_acc_md(acc);
acc_hi = read_acc_hi(acc);
result = rsp_vmadm_vmudm<true>(LOAD_VS(), LOAD_VT(), rsp_vzero(), &acc_lo, &acc_md, &acc_hi);
write_acc_lo(acc, acc_lo);
write_acc_md(acc, acc_md);
write_acc_hi(acc, acc_hi);
STORE_RESULT();
}
void RSP_VMUDM(RSP::CPUState *rsp, unsigned vd, unsigned vs, unsigned vt, unsigned e)
{
TRACE_VU(VMUDM);
uint16_t *acc = rsp->cp2.acc.e;
rsp_vect_t acc_lo, acc_md, acc_hi, result;
acc_lo = read_acc_lo(acc);
acc_md = read_acc_md(acc);
acc_hi = read_acc_hi(acc);
result = rsp_vmadm_vmudm<false>(LOAD_VS(), LOAD_VT(), rsp_vzero(), &acc_lo, &acc_md, &acc_hi);
write_acc_lo(acc, acc_lo);
write_acc_md(acc, acc_md);
write_acc_hi(acc, acc_hi);
STORE_RESULT();
}
//
// VMADN
// VMUDN
//
void RSP_VMADN(RSP::CPUState *rsp, unsigned vd, unsigned vs, unsigned vt, unsigned e)
{
TRACE_VU(VMADN);
uint16_t *acc = rsp->cp2.acc.e;
rsp_vect_t acc_lo, acc_md, acc_hi, result;
acc_lo = read_acc_lo(acc);
acc_md = read_acc_md(acc);
acc_hi = read_acc_hi(acc);
result = rsp_vmadn_vmudn<true>(LOAD_VS(), LOAD_VT(), rsp_vzero(), &acc_lo, &acc_md, &acc_hi);
write_acc_lo(acc, acc_lo);
write_acc_md(acc, acc_md);
write_acc_hi(acc, acc_hi);
STORE_RESULT();
}
void RSP_VMUDN(RSP::CPUState *rsp, unsigned vd, unsigned vs, unsigned vt, unsigned e)
{
TRACE_VU(VMUDN);
uint16_t *acc = rsp->cp2.acc.e;
rsp_vect_t acc_lo, acc_md, acc_hi, result;
acc_lo = read_acc_lo(acc);
acc_md = read_acc_md(acc);
acc_hi = read_acc_hi(acc);
result = rsp_vmadn_vmudn<false>(LOAD_VS(), LOAD_VT(), rsp_vzero(), &acc_lo, &acc_md, &acc_hi);
write_acc_lo(acc, acc_lo);
write_acc_md(acc, acc_md);
write_acc_hi(acc, acc_hi);
STORE_RESULT();
}
//
// VMOV
//
void RSP_VMOV(RSP::CPUState *rsp, unsigned vd, unsigned vs, unsigned vt, unsigned e)
{
TRACE_VU(VMOV);
uint16_t *acc = rsp->cp2.acc.e;
write_acc_lo(acc, LOAD_VT());
vs &= 0x7;
rsp->cp2.regs[vd].e[vs] = rsp->cp2.acc.e[16+vs];
}
//
// VMRG
//
void RSP_VMRG(RSP::CPUState *rsp, unsigned vd, unsigned vs, unsigned vt, unsigned e)
{
TRACE_VU(VMRG);
uint16_t *acc = rsp->cp2.acc.e;
rsp_vect_t le;
le = read_vcc_lo(rsp->cp2.flags[RSP::RSP_VCC].e);
rsp_vect_t result = rsp_vmrg(LOAD_VS(), LOAD_VT(), le);
write_vco_hi(rsp->cp2.flags[RSP::RSP_VCO].e, rsp_vzero());
write_vco_lo(rsp->cp2.flags[RSP::RSP_VCO].e, rsp_vzero());
write_acc_lo(acc, result);
STORE_RESULT();
}
//
// VMULF
// VMULQ
// VMULU
//
void RSP_VMULF(RSP::CPUState *rsp, unsigned vd, unsigned vs, unsigned vt, unsigned e)
{
TRACE_VU(VMULF);
uint16_t *acc = rsp->cp2.acc.e;
rsp_vect_t acc_lo, acc_md, acc_hi, result;
result = rsp_vmulf_vmulu<false>(LOAD_VS(), LOAD_VT(), rsp_vzero(), &acc_lo, &acc_md, &acc_hi);
write_acc_lo(acc, acc_lo);
write_acc_md(acc, acc_md);
write_acc_hi(acc, acc_hi);
STORE_RESULT();
}
void RSP_VMULQ(RSP::CPUState *rsp, unsigned vd, unsigned vs, unsigned vt, unsigned e)
{
TRACE_VU(VMULQ);
uint16_t *acc = rsp->cp2.acc.e;
uint16_t *vde = rsp->cp2.regs[vd].e;
int16_t *vse = (int16_t*)rsp->cp2.regs[vs].e;
int16_t vte[8];
rsp_vect_t vtt = LOAD_VT();
rsp_vect_write_operand((uint16_t*)vte, vtt);
for (unsigned i = 0; i < 8; i++)
{
int32_t prod = vse[i] * vte[i];
if (prod < 0) prod += 31;
acc[i] = prod >> 16;
acc[8+i] = prod & 0xffff;
acc[16+i] = 0;
vde[i] = clamp16s(prod >> 1) & ~15;
}
}
void RSP_VMULU(RSP::CPUState *rsp, unsigned vd, unsigned vs, unsigned vt, unsigned e)
{
TRACE_VU(VMULU);
uint16_t *acc = rsp->cp2.acc.e;
rsp_vect_t acc_lo, acc_md, acc_hi, result;
result = rsp_vmulf_vmulu<true>(LOAD_VS(), LOAD_VT(), rsp_vzero(), &acc_lo, &acc_md, &acc_hi);
write_acc_lo(acc, acc_lo);
write_acc_md(acc, acc_md);
write_acc_hi(acc, acc_hi);
STORE_RESULT();
}
//
// VRNDP
// VRNDN
//
static inline void RSP_VRND(RSP::CPUState *rsp, unsigned vd, unsigned vs, unsigned vt, unsigned e, uint_fast8_t variant)
{
int16_t vte[8];
rsp_vect_t vtt = LOAD_VT();
rsp_vect_write_operand((uint16_t*)vte, vtt);
uint16_t *acc = rsp->cp2.acc.e;
uint16_t *vde = rsp->cp2.regs[vd].e;
for (unsigned i = 0; i < 8; i++)
{
int64_t acc48 =
((int64_t)(int16_t)acc[i] << 32) |
((int64_t)acc[8+i] << 16) |
(int64_t)acc[16+i];
const uint_fast8_t negative_acc = acc48 < 0;
if (!!variant xor !!negative_acc)
{
int64_t value = (int64_t)(int16_t)vte[i];
if (vs & 1) value <<= 16;
acc48 += value;
}
acc[i] = (acc48 >> 32) & 0xffff;
acc[8+i] = (acc48 >> 16) & 0xffff;
acc[16+i] = acc48 & 0xffff;
vde[i] = clamp16s((int32_t)(acc48 >> 16));
}
}
void RSP_VRNDN(RSP::CPUState *rsp, unsigned vd, unsigned vs, unsigned vt, unsigned e)
{
TRACE_VU(RSP_VRNDN);
RSP_VRND(rsp, vd, vs, vt, e, 0);
}
void RSP_VRNDP(RSP::CPUState *rsp, unsigned vd, unsigned vs, unsigned vt, unsigned e)
{
TRACE_VU(RSP_VRNDP);
RSP_VRND(rsp, vd, vs, vt, e, 1);
}
//
// VNOP
//
void RSP_VNOP(RSP::CPUState *, unsigned, unsigned, unsigned, unsigned)
{
}
//
// VOR
// VNOR
//
void RSP_VOR(RSP::CPUState *rsp, unsigned vd, unsigned vs, unsigned vt, unsigned e)
{
TRACE_VU(VOR);
uint16_t *acc = rsp->cp2.acc.e;
rsp_vect_t result = rsp_vor(LOAD_VS(), LOAD_VT());
write_acc_lo(acc, result);
STORE_RESULT();
}
void RSP_VNOR(RSP::CPUState *rsp, unsigned vd, unsigned vs, unsigned vt, unsigned e)
{
TRACE_VU(VNOR);
uint16_t *acc = rsp->cp2.acc.e;
rsp_vect_t result = rsp_vnor(LOAD_VS(), LOAD_VT());
write_acc_lo(acc, result);
STORE_RESULT();
}
//
// VRCP
// VRCPL
// VRSQ
// VRSQL
//
void RSP_VRCP(RSP::CPUState *rsp, unsigned vd, unsigned vs, unsigned vt, unsigned e)
{
TRACE_VU(VRCP);
uint16_t *acc = rsp->cp2.acc.e;
unsigned de = vs & 0x7;
write_acc_lo(acc, LOAD_VT());
rsp->cp2.dp_flag = 0;
rsp_vect_t result = rsp_vrcp_vrsq<false>(rsp, 0, vt, e, vd, de);
STORE_RESULT();
}
void RSP_VRCPL(RSP::CPUState *rsp, unsigned vd, unsigned vs, unsigned vt, unsigned e)
{
TRACE_VU(VRCPL);
uint16_t *acc = rsp->cp2.acc.e;
unsigned de = vs & 0x7;
write_acc_lo(acc, LOAD_VT());
int dp = rsp->cp2.dp_flag & 1;
rsp->cp2.dp_flag = 0;
rsp_vect_t result = rsp_vrcp_vrsq<false>(rsp, dp, vt, e, vd, de);
STORE_RESULT();
}
void RSP_VRSQ(RSP::CPUState *rsp, unsigned vd, unsigned vs, unsigned vt, unsigned e)
{
TRACE_VU(VRSQ);
uint16_t *acc = rsp->cp2.acc.e;
unsigned de = vs & 0x7;
write_acc_lo(acc, LOAD_VT());
rsp->cp2.dp_flag = 0;
rsp_vect_t result = rsp_vrcp_vrsq<true>(rsp, 0, vt, e, vd, de);
STORE_RESULT();
}
void RSP_VRSQL(RSP::CPUState *rsp, unsigned vd, unsigned vs, unsigned vt, unsigned e)
{
TRACE_VU(VRSQL);
uint16_t *acc = rsp->cp2.acc.e;
unsigned de = vs & 0x7;
write_acc_lo(acc, LOAD_VT());
int dp = rsp->cp2.dp_flag & 1;
rsp->cp2.dp_flag = 0;
rsp_vect_t result = rsp_vrcp_vrsq<true>(rsp, dp, vt, e, vd, de);
STORE_RESULT();
}
//
// VRCPH
// VRSQH
//
void RSP_VRCPH(RSP::CPUState *rsp, unsigned vd, unsigned vs, unsigned vt, unsigned e)
{
TRACE_VU(VRCPH);
uint16_t *acc = rsp->cp2.acc.e;
unsigned de = vs & 0x7;
write_acc_lo(acc, LOAD_VT());
// Specify double-precision for VRCPL on the next pass.
rsp->cp2.dp_flag = 1;
rsp_vect_t result = rsp_vdivh(rsp, vt, e, vd, de);
STORE_RESULT();
}
void RSP_VRSQH(RSP::CPUState *rsp, unsigned vd, unsigned vs, unsigned vt, unsigned e)
{
TRACE_VU(VRSQH);
uint16_t *acc = rsp->cp2.acc.e;
unsigned de = vs & 0x7;
write_acc_lo(acc, LOAD_VT());
// Specify double-precision for VRCPL on the next pass.
rsp->cp2.dp_flag = 1;
rsp_vect_t result = rsp_vdivh(rsp, vt, e, vd, de);
STORE_RESULT();
}
//
// VSAR
//
void RSP_VSAR(RSP::CPUState *rsp, unsigned vd, unsigned vs, unsigned vt, unsigned e)
{
TRACE_VU(VSAR);
uint16_t *acc = rsp->cp2.acc.e;
rsp_vect_t result;
switch (e)
{
case 8:
result = read_acc_hi(acc);
break;
case 9:
result = read_acc_md(acc);
break;
case 10:
result = read_acc_lo(acc);
break;
default:
result = rsp_vzero();
break;
}
STORE_RESULT();
}
//
// VSUB
//
void RSP_VSUB(RSP::CPUState *rsp, unsigned vd, unsigned vs, unsigned vt, unsigned e)
{
TRACE_VU(VSUB);
uint16_t *acc = rsp->cp2.acc.e;
rsp_vect_t carry, acc_lo;
carry = read_vco_lo(rsp->cp2.flags[RSP::RSP_VCO].e);
rsp_vect_t result = rsp_vsub(LOAD_VS(), LOAD_VT(), carry, &acc_lo);
write_vco_hi(rsp->cp2.flags[RSP::RSP_VCO].e, rsp_vzero());
write_vco_lo(rsp->cp2.flags[RSP::RSP_VCO].e, rsp_vzero());
write_acc_lo(acc, acc_lo);
STORE_RESULT();
}
//
// VSUBC
//
void RSP_VSUBC(RSP::CPUState *rsp, unsigned vd, unsigned vs, unsigned vt, unsigned e)
{
TRACE_VU(VSUBC);
uint16_t *acc = rsp->cp2.acc.e;
rsp_vect_t eq, sn;
rsp_vect_t result = rsp_vsubc(LOAD_VS(), LOAD_VT(), rsp_vzero(), &eq, &sn);
write_vco_hi(rsp->cp2.flags[RSP::RSP_VCO].e, eq);
write_vco_lo(rsp->cp2.flags[RSP::RSP_VCO].e, sn);
write_acc_lo(acc, result);
STORE_RESULT();
}
//
// VXOR
// VNXOR
//
void RSP_VXOR(RSP::CPUState *rsp, unsigned vd, unsigned vs, unsigned vt, unsigned e)
{
TRACE_VU(VXOR);
uint16_t *acc = rsp->cp2.acc.e;
rsp_vect_t result = rsp_vxor(LOAD_VS(), LOAD_VT());
write_acc_lo(acc, result);
STORE_RESULT();
}
void RSP_VNXOR(RSP::CPUState *rsp, unsigned vd, unsigned vs, unsigned vt, unsigned e)
{
TRACE_VU(VXNOR);
uint16_t *acc = rsp->cp2.acc.e;
rsp_vect_t result = rsp_vnxor(LOAD_VS(), LOAD_VT());
write_acc_lo(acc, result);
STORE_RESULT();
}
// RESERVED
void RSP_RESERVED(RSP::CPUState *rsp, unsigned vd, unsigned vs, unsigned vt, unsigned e)
{
uint16_t *acc = rsp->cp2.acc.e;
rsp_vect_t result = _mm_add_epi16(LOAD_VS(), LOAD_VT());
write_acc_lo(acc, result);
result = rsp_vzero();
STORE_RESULT();
}
}