/* * Copyright (c) 2007 MIPS Technologies, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer; * redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution; * neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: Brett Miller */ #include "arch/mips/dsp.hh" #include "arch/mips/isa_traits.hh" #include "base/bitfield.hh" #include "base/misc.hh" #include "cpu/static_inst.hh" #include "sim/serialize.hh" using namespace MipsISA; using namespace std; int32_t MipsISA::bitrev(int32_t value) { int32_t result = 0; int shift; for (int i = 0; i < 16; i++) { shift = 2 * i - 15; if (shift < 0) result |= (value & 1 << i) << -shift; else result |= (value & 1 << i) >> shift; } return result; } uint64_t MipsISA::dspSaturate(uint64_t value, int32_t fmt, int32_t sign, uint32_t *overflow) { int64_t svalue = (int64_t)value; switch (sign) { case SIGNED: if (svalue > (int64_t)FIXED_SMAX[fmt]) { *overflow = 1; svalue = (int64_t)FIXED_SMAX[fmt]; } else if (svalue < (int64_t)FIXED_SMIN[fmt]) { *overflow = 1; svalue = (int64_t)FIXED_SMIN[fmt]; } break; case UNSIGNED: if (svalue > (int64_t)FIXED_UMAX[fmt]) { *overflow = 1; svalue = FIXED_UMAX[fmt]; } else if (svalue < (int64_t)FIXED_UMIN[fmt]) { *overflow = 1; svalue = FIXED_UMIN[fmt]; } break; } return (uint64_t)svalue; } uint64_t MipsISA::checkOverflow(uint64_t value, int32_t fmt, int32_t sign, uint32_t *overflow) { int64_t svalue = (int64_t)value; switch (sign) { case SIGNED: if (svalue > (int64_t)FIXED_SMAX[fmt] || svalue < (int64_t)FIXED_SMIN[fmt]) *overflow = 1; break; case UNSIGNED: if (svalue > (int64_t)FIXED_UMAX[fmt] || svalue < (int64_t)FIXED_UMIN[fmt]) *overflow = 1; break; } return (uint64_t)svalue; } uint64_t MipsISA::signExtend(uint64_t value, int32_t fmt) { int32_t signpos = SIMD_NBITS[fmt]; uint64_t sign = uint64_t(1) << (signpos - 1); uint64_t ones = ~(0ULL); if (value & sign) value |= (ones << signpos); // extend with ones else value &= (ones >> (64 - signpos)); // extend with zeros return value; } uint64_t MipsISA::addHalfLsb(uint64_t value, int32_t lsbpos) { return value += ULL(1) << (lsbpos - 1); } int32_t MipsISA::dspAbs(int32_t a, int32_t fmt, uint32_t *dspctl) { int nvals = SIMD_NVALS[fmt]; int32_t result; int64_t svalue; uint32_t ouflag = 0; uint64_t a_values[SIMD_MAX_VALS]; simdUnpack(a, a_values, fmt, SIGNED); for (int i = 0; i < nvals; i++) { svalue = (int64_t)a_values[i]; if (a_values[i] == FIXED_SMIN[fmt]) { a_values[i] = FIXED_SMAX[fmt]; ouflag = 1; } else if (svalue < 0) { a_values[i] = uint64_t(0 - svalue); } } simdPack(a_values, &result, fmt); if (ouflag) writeDSPControl(dspctl, (ouflag << 4) << DSP_CTL_POS[DSP_OUFLAG], 1 << DSP_OUFLAG); return result; } int32_t MipsISA::dspAdd(int32_t a, int32_t b, int32_t fmt, int32_t saturate, int32_t sign, uint32_t *dspctl) { int nvals = SIMD_NVALS[fmt]; int32_t result; uint32_t ouflag = 0; uint64_t a_values[SIMD_MAX_VALS]; uint64_t b_values[SIMD_MAX_VALS]; simdUnpack(a, a_values, fmt, sign); simdUnpack(b, b_values, fmt, sign); for (int i = 0; i < nvals; i++) { if (saturate) a_values[i] = dspSaturate(a_values[i] + b_values[i], fmt, sign, &ouflag); else a_values[i] = checkOverflow(a_values[i] + b_values[i], fmt, sign, &ouflag); } simdPack(a_values, &result, fmt); if (ouflag) writeDSPControl(dspctl, (ouflag << 4) << DSP_CTL_POS[DSP_OUFLAG], 1 << DSP_OUFLAG); return result; } int32_t MipsISA::dspAddh(int32_t a, int32_t b, int32_t fmt, int32_t round, int32_t sign) { int nvals = SIMD_NVALS[fmt]; int32_t result; uint64_t a_values[SIMD_MAX_VALS]; uint64_t b_values[SIMD_MAX_VALS]; simdUnpack(a, a_values, fmt, sign); simdUnpack(b, b_values, fmt, sign); for (int i = 0; i < nvals; i++) { if (round) a_values[i] = addHalfLsb(a_values[i] + b_values[i], 1) >> 1; else a_values[i] = (a_values[i] + b_values[i]) >> 1; } simdPack(a_values, &result, fmt); return result; } int32_t MipsISA::dspSub(int32_t a, int32_t b, int32_t fmt, int32_t saturate, int32_t sign, uint32_t *dspctl) { int nvals = SIMD_NVALS[fmt]; int32_t result; uint32_t ouflag = 0; uint64_t a_values[SIMD_MAX_VALS]; uint64_t b_values[SIMD_MAX_VALS]; simdUnpack(a, a_values, fmt, sign); simdUnpack(b, b_values, fmt, sign); for (int i = 0; i < nvals; i++) { if (saturate) a_values[i] = dspSaturate(a_values[i] - b_values[i], fmt, sign, &ouflag); else a_values[i] = checkOverflow(a_values[i] - b_values[i], fmt, sign, &ouflag); } simdPack(a_values, &result, fmt); if (ouflag) writeDSPControl(dspctl, (ouflag << 4) << DSP_CTL_POS[DSP_OUFLAG], 1 << DSP_OUFLAG); return result; } int32_t MipsISA::dspSubh(int32_t a, int32_t b, int32_t fmt, int32_t round, int32_t sign) { int nvals = SIMD_NVALS[fmt]; int32_t result; uint64_t a_values[SIMD_MAX_VALS]; uint64_t b_values[SIMD_MAX_VALS]; simdUnpack(a, a_values, fmt, sign); simdUnpack(b, b_values, fmt, sign); for (int i = 0; i < nvals; i++) { if (round) a_values[i] = addHalfLsb(a_values[i] - b_values[i], 1) >> 1; else a_values[i] = (a_values[i] - b_values[i]) >> 1; } simdPack(a_values, &result, fmt); return result; } int32_t MipsISA::dspShll(int32_t a, uint32_t sa, int32_t fmt, int32_t saturate, int32_t sign, uint32_t *dspctl) { int nvals = SIMD_NVALS[fmt]; int32_t result; uint32_t ouflag = 0; uint64_t a_values[SIMD_MAX_VALS]; sa = bits(sa, SIMD_LOG2N[fmt] - 1, 0); simdUnpack(a, a_values, fmt, sign); for (int i = 0; i < nvals; i++) { if (saturate) a_values[i] = dspSaturate(a_values[i] << sa, fmt, sign, &ouflag); else a_values[i] = checkOverflow(a_values[i] << sa, fmt, sign, &ouflag); } simdPack(a_values, &result, fmt); if (ouflag) writeDSPControl(dspctl, (ouflag << 6) << DSP_CTL_POS[DSP_OUFLAG], 1 << DSP_OUFLAG); return result; } int32_t MipsISA::dspShrl(int32_t a, uint32_t sa, int32_t fmt, int32_t sign) { int nvals = SIMD_NVALS[fmt]; int32_t result; uint64_t a_values[SIMD_MAX_VALS]; sa = bits(sa, SIMD_LOG2N[fmt] - 1, 0); simdUnpack(a, a_values, fmt, UNSIGNED); for (int i = 0; i < nvals; i++) a_values[i] = a_values[i] >> sa; simdPack(a_values, &result, fmt); return result; } int32_t MipsISA::dspShra(int32_t a, uint32_t sa, int32_t fmt, int32_t round, int32_t sign, uint32_t *dspctl) { int nvals = SIMD_NVALS[fmt]; int32_t result; uint64_t a_values[SIMD_MAX_VALS]; sa = bits(sa, SIMD_LOG2N[fmt] - 1, 0); simdUnpack(a, a_values, fmt, SIGNED); for (int i = 0; i < nvals; i++) { if (round) a_values[i] = addHalfLsb(a_values[i], sa) >> sa; else a_values[i] = a_values[i] >> sa; } simdPack(a_values, &result, fmt); return result; } int32_t MipsISA::dspMulq(int32_t a, int32_t b, int32_t fmt, int32_t saturate, int32_t round, uint32_t *dspctl) { int nvals = SIMD_NVALS[fmt]; int sa = SIMD_NBITS[fmt]; int32_t result; uint32_t ouflag = 0; uint64_t a_values[SIMD_MAX_VALS]; uint64_t b_values[SIMD_MAX_VALS]; int64_t temp; simdUnpack(a, a_values, fmt, SIGNED); simdUnpack(b, b_values, fmt, SIGNED); for (int i = 0; i < nvals; i++) { if (round) temp = (int64_t)addHalfLsb(a_values[i] * b_values[i] << 1, sa) >> sa; else temp = (int64_t)(a_values[i] * b_values[i]) >> (sa - 1); if (a_values[i] == FIXED_SMIN[fmt] && b_values[i] == FIXED_SMIN[fmt]) { ouflag = 1; if (saturate) temp = FIXED_SMAX[fmt]; } a_values[i] = temp; } simdPack(a_values, &result, fmt); if (ouflag) writeDSPControl(dspctl, (ouflag << 5) << DSP_CTL_POS[DSP_OUFLAG], 1 << DSP_OUFLAG); return result; } int32_t MipsISA::dspMul(int32_t a, int32_t b, int32_t fmt, int32_t saturate, uint32_t *dspctl) { int nvals = SIMD_NVALS[fmt]; int32_t result; uint32_t ouflag = 0; uint64_t a_values[SIMD_MAX_VALS]; uint64_t b_values[SIMD_MAX_VALS]; simdUnpack(a, a_values, fmt, SIGNED); simdUnpack(b, b_values, fmt, SIGNED); for (int i = 0; i < nvals; i++) { if (saturate) a_values[i] = dspSaturate(a_values[i] * b_values[i], fmt, SIGNED, &ouflag); else a_values[i] = checkOverflow(a_values[i] * b_values[i], fmt, SIGNED, &ouflag); } simdPack(a_values, &result, fmt); if (ouflag) writeDSPControl(dspctl, (ouflag << 5) << DSP_CTL_POS[DSP_OUFLAG], 1 << DSP_OUFLAG); return result; } int32_t MipsISA::dspMuleu(int32_t a, int32_t b, int32_t mode, uint32_t *dspctl) { int nvals = SIMD_NVALS[SIMD_FMT_PH]; int32_t result; uint32_t ouflag = 0; uint64_t a_values[SIMD_MAX_VALS]; uint64_t b_values[SIMD_MAX_VALS]; simdUnpack(a, a_values, SIMD_FMT_QB, UNSIGNED); simdUnpack(b, b_values, SIMD_FMT_PH, UNSIGNED); switch (mode) { case MODE_L: for (int i = 0; i < nvals; i++) b_values[i] = dspSaturate(a_values[i + 2] * b_values[i], SIMD_FMT_PH, UNSIGNED, &ouflag); break; case MODE_R: for (int i = 0; i < nvals; i++) b_values[i] = dspSaturate(a_values[i] * b_values[i], SIMD_FMT_PH, UNSIGNED, &ouflag); break; } simdPack(b_values, &result, SIMD_FMT_PH); if (ouflag) writeDSPControl(dspctl, (ouflag << 5) << DSP_CTL_POS[DSP_OUFLAG], 1 << DSP_OUFLAG); return result; } int32_t MipsISA::dspMuleq(int32_t a, int32_t b, int32_t mode, uint32_t *dspctl) { int nvals = SIMD_NVALS[SIMD_FMT_W]; int32_t result; uint32_t ouflag = 0; uint64_t a_values[SIMD_MAX_VALS]; uint64_t b_values[SIMD_MAX_VALS]; uint64_t c_values[SIMD_MAX_VALS]; memset(c_values, 0, sizeof(c_values)); simdUnpack(a, a_values, SIMD_FMT_PH, SIGNED); simdUnpack(b, b_values, SIMD_FMT_PH, SIGNED); switch (mode) { case MODE_L: for (int i = 0; i < nvals; i++) c_values[i] = dspSaturate(a_values[i + 1] * b_values[i + 1] << 1, SIMD_FMT_W, SIGNED, &ouflag); break; case MODE_R: for (int i = 0; i < nvals; i++) c_values[i] = dspSaturate(a_values[i] * b_values[i] << 1, SIMD_FMT_W, SIGNED, &ouflag); break; } simdPack(c_values, &result, SIMD_FMT_W); if (ouflag) writeDSPControl(dspctl, (ouflag << 5) << DSP_CTL_POS[DSP_OUFLAG], 1 << DSP_OUFLAG); return result; } int64_t MipsISA::dspDpaq(int64_t dspac, int32_t a, int32_t b, int32_t ac, int32_t infmt, int32_t outfmt, int32_t postsat, int32_t mode, uint32_t *dspctl) { int nvals = SIMD_NVALS[infmt]; int64_t result = 0; int64_t temp = 0; uint32_t ouflag = 0; uint64_t a_values[SIMD_MAX_VALS]; uint64_t b_values[SIMD_MAX_VALS]; simdUnpack(a, a_values, infmt, SIGNED); simdUnpack(b, b_values, infmt, SIGNED); for (int i = 0; i < nvals; i++) { switch (mode) { case MODE_X: if (a_values[nvals - 1 - i] == FIXED_SMIN[infmt] && b_values[i] == FIXED_SMIN[infmt]) { result += FIXED_SMAX[outfmt]; ouflag = 1; } else result += a_values[nvals - 1 - i] * b_values[i] << 1; break; default: if (a_values[i] == FIXED_SMIN[infmt] && b_values[i] == FIXED_SMIN[infmt]) { result += FIXED_SMAX[outfmt]; ouflag = 1; } else { result += a_values[i] * b_values[i] << 1; } break; } } if (postsat) { if (outfmt == SIMD_FMT_L) { int signa = bits(dspac, 63, 63); int signb = bits(result, 63, 63); temp = dspac + result; if (signa == signb && bits(temp, 63, 63) != signa) { ouflag = 1; if (signa) dspac = FIXED_SMIN[outfmt]; else dspac = FIXED_SMAX[outfmt]; } else { dspac = temp; } } else { dspac = dspSaturate(dspac + result, outfmt, SIGNED, &ouflag); } } else { dspac += result; } if (ouflag) *dspctl = insertBits(*dspctl, 16 + ac, 16 + ac, 1); return dspac; } int64_t MipsISA::dspDpsq(int64_t dspac, int32_t a, int32_t b, int32_t ac, int32_t infmt, int32_t outfmt, int32_t postsat, int32_t mode, uint32_t *dspctl) { int nvals = SIMD_NVALS[infmt]; int64_t result = 0; int64_t temp = 0; uint32_t ouflag = 0; uint64_t a_values[SIMD_MAX_VALS]; uint64_t b_values[SIMD_MAX_VALS]; simdUnpack(a, a_values, infmt, SIGNED); simdUnpack(b, b_values, infmt, SIGNED); for (int i = 0; i < nvals; i++) { switch (mode) { case MODE_X: if (a_values[nvals - 1 - i] == FIXED_SMIN[infmt] && b_values[i] == FIXED_SMIN[infmt]) { result += FIXED_SMAX[outfmt]; ouflag = 1; } else { result += a_values[nvals - 1 - i] * b_values[i] << 1; } break; default: if (a_values[i] == FIXED_SMIN[infmt] && b_values[i] == FIXED_SMIN[infmt]) { result += FIXED_SMAX[outfmt]; ouflag = 1; } else { result += a_values[i] * b_values[i] << 1; } break; } } if (postsat) { if (outfmt == SIMD_FMT_L) { int signa = bits(dspac, 63, 63); int signb = bits(-result, 63, 63); temp = dspac - result; if (signa == signb && bits(temp, 63, 63) != signa) { ouflag = 1; if (signa) dspac = FIXED_SMIN[outfmt]; else dspac = FIXED_SMAX[outfmt]; } else { dspac = temp; } } else { dspac = dspSaturate(dspac - result, outfmt, SIGNED, &ouflag); } } else { dspac -= result; } if (ouflag) *dspctl = insertBits(*dspctl, 16 + ac, 16 + ac, 1); return dspac; } int64_t MipsISA::dspDpa(int64_t dspac, int32_t a, int32_t b, int32_t ac, int32_t fmt, int32_t sign, int32_t mode) { int nvals = SIMD_NVALS[fmt]; uint64_t a_values[SIMD_MAX_VALS]; uint64_t b_values[SIMD_MAX_VALS]; simdUnpack(a, a_values, fmt, sign); simdUnpack(b, b_values, fmt, sign); for (int i = 0; i < 2; i++) { switch (mode) { case MODE_L: dspac += a_values[nvals - 1 - i] * b_values[nvals - 1 - i]; break; case MODE_R: dspac += a_values[nvals - 3 - i] * b_values[nvals - 3 - i]; break; case MODE_X: dspac += a_values[nvals - 1 - i] * b_values[i]; break; } } return dspac; } int64_t MipsISA::dspDps(int64_t dspac, int32_t a, int32_t b, int32_t ac, int32_t fmt, int32_t sign, int32_t mode) { int nvals = SIMD_NVALS[fmt]; uint64_t a_values[SIMD_MAX_VALS]; uint64_t b_values[SIMD_MAX_VALS]; simdUnpack(a, a_values, fmt, sign); simdUnpack(b, b_values, fmt, sign); for (int i = 0; i < 2; i++) { switch (mode) { case MODE_L: dspac -= a_values[nvals - 1 - i] * b_values[nvals - 1 - i]; break; case MODE_R: dspac -= a_values[nvals - 3 - i] * b_values[nvals - 3 - i]; break; case MODE_X: dspac -= a_values[nvals - 1 - i] * b_values[i]; break; } } return dspac; } int64_t MipsISA::dspMaq(int64_t dspac, int32_t a, int32_t b, int32_t ac, int32_t fmt, int32_t mode, int32_t saturate, uint32_t *dspctl) { int nvals = SIMD_NVALS[fmt - 1]; uint64_t a_values[SIMD_MAX_VALS]; uint64_t b_values[SIMD_MAX_VALS]; int64_t temp = 0; uint32_t ouflag = 0; simdUnpack(a, a_values, fmt, SIGNED); simdUnpack(b, b_values, fmt, SIGNED); for (int i = 0; i < nvals; i++) { switch (mode) { case MODE_L: temp = a_values[i + 1] * b_values[i + 1] << 1; if (a_values[i + 1] == FIXED_SMIN[fmt] && b_values[i + 1] == FIXED_SMIN[fmt]) { temp = (int64_t)FIXED_SMAX[fmt - 1]; ouflag = 1; } break; case MODE_R: temp = a_values[i] * b_values[i] << 1; if (a_values[i] == FIXED_SMIN[fmt] && b_values[i] == FIXED_SMIN[fmt]) { temp = (int64_t)FIXED_SMAX[fmt - 1]; ouflag = 1; } break; } temp += dspac; if (saturate) temp = dspSaturate(temp, fmt - 1, SIGNED, &ouflag); if (ouflag) *dspctl = insertBits(*dspctl, 16 + ac, 16 + ac, 1); } return temp; } int64_t MipsISA::dspMulsa(int64_t dspac, int32_t a, int32_t b, int32_t ac, int32_t fmt) { uint64_t a_values[SIMD_MAX_VALS]; uint64_t b_values[SIMD_MAX_VALS]; simdUnpack(a, a_values, fmt, SIGNED); simdUnpack(b, b_values, fmt, SIGNED); dspac += a_values[1] * b_values[1] - a_values[0] * b_values[0]; return dspac; } int64_t MipsISA::dspMulsaq(int64_t dspac, int32_t a, int32_t b, int32_t ac, int32_t fmt, uint32_t *dspctl) { int nvals = SIMD_NVALS[fmt]; uint64_t a_values[SIMD_MAX_VALS]; uint64_t b_values[SIMD_MAX_VALS]; int64_t temp[2] = {0, 0}; uint32_t ouflag = 0; simdUnpack(a, a_values, fmt, SIGNED); simdUnpack(b, b_values, fmt, SIGNED); for (int i = nvals - 1; i > -1; i--) { temp[i] = a_values[i] * b_values[i] << 1; if (a_values[i] == FIXED_SMIN[fmt] && b_values[i] == FIXED_SMIN[fmt]) { temp[i] = FIXED_SMAX[fmt - 1]; ouflag = 1; } } dspac += temp[1] - temp[0]; if (ouflag) *dspctl = insertBits(*dspctl, 16 + ac, 16 + ac, 1); return dspac; } void MipsISA::dspCmp(int32_t a, int32_t b, int32_t fmt, int32_t sign, int32_t op, uint32_t *dspctl) { int nvals = SIMD_NVALS[fmt]; int ccond = 0; uint64_t a_values[SIMD_MAX_VALS]; uint64_t b_values[SIMD_MAX_VALS]; simdUnpack(a, a_values, fmt, sign); simdUnpack(b, b_values, fmt, sign); for (int i = 0; i < nvals; i++) { int cc = 0; switch (op) { case CMP_EQ: cc = (a_values[i] == b_values[i]); break; case CMP_LT: cc = (a_values[i] < b_values[i]); break; case CMP_LE: cc = (a_values[i] <= b_values[i]); break; } ccond |= cc << (DSP_CTL_POS[DSP_CCOND] + i); } writeDSPControl(dspctl, ccond, 1 << DSP_CCOND); } int32_t MipsISA::dspCmpg(int32_t a, int32_t b, int32_t fmt, int32_t sign, int32_t op) { int nvals = SIMD_NVALS[fmt]; int32_t result = 0; uint64_t a_values[SIMD_MAX_VALS]; uint64_t b_values[SIMD_MAX_VALS]; simdUnpack(a, a_values, fmt, sign); simdUnpack(b, b_values, fmt, sign); for (int i = 0; i < nvals; i++) { int cc = 0; switch (op) { case CMP_EQ: cc = (a_values[i] == b_values[i]); break; case CMP_LT: cc = (a_values[i] < b_values[i]); break; case CMP_LE: cc = (a_values[i] <= b_values[i]); break; } result |= cc << i; } return result; } int32_t MipsISA::dspCmpgd(int32_t a, int32_t b, int32_t fmt, int32_t sign, int32_t op, uint32_t *dspctl) { int nvals = SIMD_NVALS[fmt]; int32_t result = 0; int ccond = 0; uint64_t a_values[SIMD_MAX_VALS]; uint64_t b_values[SIMD_MAX_VALS]; simdUnpack(a, a_values, fmt, sign); simdUnpack(b, b_values, fmt, sign); for (int i = 0; i < nvals; i++) { int cc = 0; switch (op) { case CMP_EQ: cc = (a_values[i] == b_values[i]); break; case CMP_LT: cc = (a_values[i] < b_values[i]); break; case CMP_LE: cc = (a_values[i] <= b_values[i]); break; } result |= cc << i; ccond |= cc << (DSP_CTL_POS[DSP_CCOND] + i); } writeDSPControl(dspctl, ccond, 1 << DSP_CCOND); return result; } int32_t MipsISA::dspPrece(int32_t a, int32_t infmt, int32_t insign, int32_t outfmt, int32_t outsign, int32_t mode) { int sa = 0; int ninvals = SIMD_NVALS[infmt]; int noutvals = SIMD_NVALS[outfmt]; int32_t result; uint64_t in_values[SIMD_MAX_VALS]; uint64_t out_values[SIMD_MAX_VALS]; if (insign == SIGNED && outsign == SIGNED) sa = SIMD_NBITS[infmt]; else if (insign == UNSIGNED && outsign == SIGNED) sa = SIMD_NBITS[infmt] - 1; else if (insign == UNSIGNED && outsign == UNSIGNED) sa = 0; simdUnpack(a, in_values, infmt, insign); for (int i = 0; i> 1)] << sa; break; case MODE_R: out_values[i] = in_values[i] << sa; break; case MODE_LA: out_values[i] = in_values[(i << 1) + 1] << sa; break; case MODE_RA: out_values[i] = in_values[i << 1] << sa; break; } } simdPack(out_values, &result, outfmt); return result; } int32_t MipsISA::dspPrecrqu(int32_t a, int32_t b, uint32_t *dspctl) { uint64_t a_values[SIMD_MAX_VALS]; uint64_t b_values[SIMD_MAX_VALS]; uint64_t r_values[SIMD_MAX_VALS]; uint32_t ouflag = 0; int32_t result = 0; simdUnpack(a, a_values, SIMD_FMT_PH, SIGNED); simdUnpack(b, b_values, SIMD_FMT_PH, SIGNED); for (int i = 0; i<2; i++) { r_values[i] = dspSaturate((int64_t)b_values[i] >> (SIMD_NBITS[SIMD_FMT_QB] - 1), SIMD_FMT_QB, UNSIGNED, &ouflag); r_values[i + 2] = dspSaturate((int64_t)a_values[i] >> (SIMD_NBITS[SIMD_FMT_QB] - 1), SIMD_FMT_QB, UNSIGNED, &ouflag); } simdPack(r_values, &result, SIMD_FMT_QB); if (ouflag) *dspctl = insertBits(*dspctl, 22, 22, 1); return result; } int32_t MipsISA::dspPrecrq(int32_t a, int32_t b, int32_t fmt, uint32_t *dspctl) { uint64_t a_values[SIMD_MAX_VALS]; uint64_t b_values[SIMD_MAX_VALS]; uint64_t r_values[SIMD_MAX_VALS]; uint32_t ouflag = 0; int32_t result; simdUnpack(a, a_values, fmt, SIGNED); simdUnpack(b, b_values, fmt, SIGNED); r_values[1] = dspSaturate((int64_t)addHalfLsb(a_values[0], 16) >> 16, fmt + 1, SIGNED, &ouflag); r_values[0] = dspSaturate((int64_t)addHalfLsb(b_values[0], 16) >> 16, fmt + 1, SIGNED, &ouflag); simdPack(r_values, &result, fmt + 1); if (ouflag) *dspctl = insertBits(*dspctl, 22, 22, 1); return result; } int32_t MipsISA::dspPrecrSra(int32_t a, int32_t b, int32_t sa, int32_t fmt, int32_t round) { int nvals = SIMD_NVALS[fmt]; uint64_t a_values[SIMD_MAX_VALS]; uint64_t b_values[SIMD_MAX_VALS]; uint64_t c_values[SIMD_MAX_VALS]; int32_t result = 0; simdUnpack(a, a_values, fmt, SIGNED); simdUnpack(b, b_values, fmt, SIGNED); for (int i = 0; i < nvals; i++) { if (round) { c_values[i] = addHalfLsb(b_values[i], sa) >> sa; c_values[i + 1] = addHalfLsb(a_values[i], sa) >> sa; } else { c_values[i] = b_values[i] >> sa; c_values[i + 1] = a_values[i] >> sa; } } simdPack(c_values, &result, fmt + 1); return result; } int32_t MipsISA::dspPick(int32_t a, int32_t b, int32_t fmt, uint32_t *dspctl) { int nvals = SIMD_NVALS[fmt]; int32_t result; uint64_t a_values[SIMD_MAX_VALS]; uint64_t b_values[SIMD_MAX_VALS]; uint64_t c_values[SIMD_MAX_VALS]; simdUnpack(a, a_values, fmt, UNSIGNED); simdUnpack(b, b_values, fmt, UNSIGNED); for (int i = 0; i < nvals; i++) { int condbit = DSP_CTL_POS[DSP_CCOND] + i; if (bits(*dspctl, condbit, condbit) == 1) c_values[i] = a_values[i]; else c_values[i] = b_values[i]; } simdPack(c_values, &result, fmt); return result; } int32_t MipsISA::dspPack(int32_t a, int32_t b, int32_t fmt) { int32_t result; uint64_t a_values[SIMD_MAX_VALS]; uint64_t b_values[SIMD_MAX_VALS]; uint64_t c_values[SIMD_MAX_VALS]; simdUnpack(a, a_values, fmt, UNSIGNED); simdUnpack(b, b_values, fmt, UNSIGNED); c_values[0] = b_values[1]; c_values[1] = a_values[0]; simdPack(c_values, &result, fmt); return result; } int32_t MipsISA::dspExtr(int64_t dspac, int32_t fmt, int32_t sa, int32_t round, int32_t saturate, uint32_t *dspctl) { int32_t result = 0; uint32_t ouflag = 0; int64_t temp = 0; sa = bits(sa, 4, 0); if (sa > 0) { if (round) { temp = (int64_t)addHalfLsb(dspac, sa); if (dspac > 0 && temp < 0) { ouflag = 1; if (saturate) temp = FIXED_SMAX[SIMD_FMT_L]; } temp = temp >> sa; } else { temp = dspac >> sa; } } else { temp = dspac; } dspac = checkOverflow(dspac, fmt, SIGNED, &ouflag); if (ouflag) { *dspctl = insertBits(*dspctl, 23, 23, ouflag); if (saturate) result = (int32_t)dspSaturate(temp, fmt, SIGNED, &ouflag); else result = (int32_t)temp; } else { result = (int32_t)temp; } return result; } int32_t MipsISA::dspExtp(int64_t dspac, int32_t size, uint32_t *dspctl) { int32_t pos = 0; int32_t result = 0; pos = bits(*dspctl, 5, 0); size = bits(size, 4, 0); if (pos - (size + 1) >= -1) { result = bits(dspac, pos, pos - size); *dspctl = insertBits(*dspctl, 14, 14, 0); } else { result = 0; *dspctl = insertBits(*dspctl, 14, 14, 1); } return result; } int32_t MipsISA::dspExtpd(int64_t dspac, int32_t size, uint32_t *dspctl) { int32_t pos = 0; int32_t result = 0; pos = bits(*dspctl, 5, 0); size = bits(size, 4, 0); if (pos - (size + 1) >= -1) { result = bits(dspac, pos, pos - size); *dspctl = insertBits(*dspctl, 14, 14, 0); if (pos - (size + 1) >= 0) *dspctl = insertBits(*dspctl, 5, 0, pos - (size + 1)); else if ((pos - (size + 1)) == -1) *dspctl = insertBits(*dspctl, 5, 0, 63); } else { result = 0; *dspctl = insertBits(*dspctl, 14, 14, 1); } return result; } void MipsISA::simdPack(uint64_t *values_ptr, int32_t *reg, int32_t fmt) { int nvals = SIMD_NVALS[fmt]; int nbits = SIMD_NBITS[fmt]; *reg = 0; for (int i = 0; i < nvals; i++) *reg |= (int32_t)bits(values_ptr[i], nbits - 1, 0) << nbits * i; } void MipsISA::simdUnpack(int32_t reg, uint64_t *values_ptr, int32_t fmt, int32_t sign) { int nvals = SIMD_NVALS[fmt]; int nbits = SIMD_NBITS[fmt]; switch (sign) { case SIGNED: for (int i = 0; i < nvals; i++) { uint64_t tmp = (uint64_t)bits(reg, nbits * (i + 1) - 1, nbits * i); values_ptr[i] = signExtend(tmp, fmt); } break; case UNSIGNED: for (int i = 0; i < nvals; i++) { values_ptr[i] = (uint64_t)bits(reg, nbits * (i + 1) - 1, nbits * i); } break; } } void MipsISA::writeDSPControl(uint32_t *dspctl, uint32_t value, uint32_t mask) { uint32_t fmask = 0; if (mask & 0x01) fmask |= DSP_CTL_MASK[DSP_POS]; if (mask & 0x02) fmask |= DSP_CTL_MASK[DSP_SCOUNT]; if (mask & 0x04) fmask |= DSP_CTL_MASK[DSP_C]; if (mask & 0x08) fmask |= DSP_CTL_MASK[DSP_OUFLAG]; if (mask & 0x10) fmask |= DSP_CTL_MASK[DSP_CCOND]; if (mask & 0x20) fmask |= DSP_CTL_MASK[DSP_EFI]; *dspctl &= ~fmask; value &= fmask; *dspctl |= value; } uint32_t MipsISA::readDSPControl(uint32_t *dspctl, uint32_t mask) { uint32_t fmask = 0; if (mask & 0x01) fmask |= DSP_CTL_MASK[DSP_POS]; if (mask & 0x02) fmask |= DSP_CTL_MASK[DSP_SCOUNT]; if (mask & 0x04) fmask |= DSP_CTL_MASK[DSP_C]; if (mask & 0x08) fmask |= DSP_CTL_MASK[DSP_OUFLAG]; if (mask & 0x10) fmask |= DSP_CTL_MASK[DSP_CCOND]; if (mask & 0x20) fmask |= DSP_CTL_MASK[DSP_EFI]; return *dspctl & fmask; }