diff options
Diffstat (limited to 'src/arch/mips/dsp.cc')
-rwxr-xr-x | src/arch/mips/dsp.cc | 1227 |
1 files changed, 1227 insertions, 0 deletions
diff --git a/src/arch/mips/dsp.cc b/src/arch/mips/dsp.cc new file mode 100755 index 000000000..059c15a32 --- /dev/null +++ b/src/arch/mips/dsp.cc @@ -0,0 +1,1227 @@ +/* + * Copyright (c) 2003-2006 The Regents of The University of Michigan + * 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/isa_traits.hh" +#include "arch/mips/dsp.hh" +#include "arch/mips/constants.hh" +#include "config/full_system.hh" +#include "cpu/static_inst.hh" +#include "sim/serialize.hh" +#include "base/bitfield.hh" +#include "base/misc.hh" + +using namespace MipsISA; +using namespace std; + +int32_t +MipsISA::bitrev( int32_t value ) +{ + int32_t result = 0; + int i, shift; + + for( i=0; i<16; i++ ) + { + shift = 2*i - 15; + + if( shift < 0 ) + result |= (value & 1L<<i) << -shift; + else + result |= (value & 1L<<i) >> shift; + } + + return result; +} + +uint64_t +MipsISA::dspSaturate( uint64_t value, int32_t fmt, int32_t sign, uint32_t *overflow ) +{ + int64_t svalue; + + 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; + + 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 i = 0; + 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( 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 i = 0; + 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( 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 i = 0; + 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( 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 i = 0; + 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( 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 i = 0; + 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( 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 i = 0; + 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( 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 i = 0; + 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( 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 i = 0; + 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( 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 i = 0; + 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( 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 i = 0; + 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( 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 i = 0; + 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( 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( 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 i = 0; + 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]; + + simdUnpack( a, a_values, SIMD_FMT_PH, SIGNED ); + simdUnpack( b, b_values, SIMD_FMT_PH, SIGNED ); + + switch( mode ) + { + case MODE_L: + for( 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( 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 i = 0; + 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( 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 i = 0; + 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( 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 i = 0; + 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( 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 i = 0; + 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( 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 i = 0; + 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( 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 i = 0; + int nvals = SIMD_NVALS[fmt]; + uint64_t a_values[SIMD_MAX_VALS]; + uint64_t b_values[SIMD_MAX_VALS]; + int64_t temp[2]; + uint32_t ouflag = 0; + + simdUnpack( a, a_values, fmt, SIGNED ); + simdUnpack( b, b_values, fmt, SIGNED ); + + for( 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 i = 0; + 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( 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 i = 0; + 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( 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 i = 0;; + 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( 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 i = 0; + 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( i=0; i<noutvals; i++ ) + { + switch( mode ) + { + case MODE_L: out_values[i] = in_values[i+(ninvals>>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 ) +{ + int i = 0; + 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( 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 i = 0; + 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( 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 i = 0; + 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( 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 i = 0; + int nvals = SIMD_NVALS[fmt]; + int nbits = SIMD_NBITS[fmt]; + + *reg = 0; + + for( 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 i = 0; + int nvals = SIMD_NVALS[fmt]; + int nbits = SIMD_NBITS[fmt]; + + switch( sign ) + { + case SIGNED: + for( i=0; i<nvals; i++ ) + { + values_ptr[i] = (uint64_t)bits( reg, nbits*(i+1)-1, nbits*i ); + values_ptr[i] = signExtend( values_ptr[i], fmt ); + } + break; + case UNSIGNED: + for( 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 ); +} |