/// Copyright (c) 2009 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: Gabe Black

def template MediaOpExecute {{
        Fault %(class_name)s::execute(%(CPU_exec_context)s *xc,
                Trace::InstRecord *traceData) const
        {
            Fault fault = NoFault;

            %(op_decl)s;
            %(op_rd)s;

            %(code)s;

            //Write the resulting state to the execution context
            if(fault == NoFault)
            {
                %(op_wb)s;
            }
            return fault;
        }
}};

def template MediaOpRegDeclare {{
    class %(class_name)s : public %(base_class)s
    {
      protected:
        void buildMe();

      public:
        %(class_name)s(ExtMachInst _machInst,
                const char * instMnem,
                bool isMicro, bool isDelayed, bool isFirst, bool isLast,
                InstRegIndex _src1, InstRegIndex _src2, InstRegIndex _dest,
                uint8_t _srcSize, uint8_t _destSize, uint16_t _ext);

        %(class_name)s(ExtMachInst _machInst,
                const char * instMnem,
                InstRegIndex _src1, InstRegIndex _src2, InstRegIndex _dest,
                uint8_t _srcSize, uint8_t _destSize, uint16_t _ext);

        %(BasicExecDeclare)s
    };
}};

def template MediaOpImmDeclare {{

    class %(class_name)s : public %(base_class)s
    {
      protected:
        void buildMe();

      public:
        %(class_name)s(ExtMachInst _machInst,
                const char * instMnem,
                bool isMicro, bool isDelayed, bool isFirst, bool isLast,
                InstRegIndex _src1, uint16_t _imm8, InstRegIndex _dest,
                uint8_t _srcSize, uint8_t _destSize, uint16_t _ext);

        %(class_name)s(ExtMachInst _machInst,
                const char * instMnem,
                InstRegIndex _src1, uint16_t _imm8, InstRegIndex _dest,
                uint8_t _srcSize, uint8_t _destSize, uint16_t _ext);

        %(BasicExecDeclare)s
    };
}};

def template MediaOpRegConstructor {{

    inline void %(class_name)s::buildMe()
    {
        %(constructor)s;
    }

    inline %(class_name)s::%(class_name)s(
            ExtMachInst machInst, const char * instMnem,
            InstRegIndex _src1, InstRegIndex _src2, InstRegIndex _dest,
            uint8_t _srcSize, uint8_t _destSize, uint16_t _ext) :
        %(base_class)s(machInst, "%(mnemonic)s", instMnem,
                false, false, false, false,
                _src1, _src2, _dest, _srcSize, _destSize, _ext,
                %(op_class)s)
    {
        buildMe();
    }

    inline %(class_name)s::%(class_name)s(
            ExtMachInst machInst, const char * instMnem,
            bool isMicro, bool isDelayed, bool isFirst, bool isLast,
            InstRegIndex _src1, InstRegIndex _src2, InstRegIndex _dest,
            uint8_t _srcSize, uint8_t _destSize, uint16_t _ext) :
        %(base_class)s(machInst, "%(mnemonic)s", instMnem,
                isMicro, isDelayed, isFirst, isLast,
                _src1, _src2, _dest, _srcSize, _destSize, _ext,
                %(op_class)s)
    {
        buildMe();
    }
}};

def template MediaOpImmConstructor {{

    inline void %(class_name)s::buildMe()
    {
        %(constructor)s;
    }

    inline %(class_name)s::%(class_name)s(
            ExtMachInst machInst, const char * instMnem,
            InstRegIndex _src1, uint16_t _imm8, InstRegIndex _dest,
            uint8_t _srcSize, uint8_t _destSize, uint16_t _ext) :
        %(base_class)s(machInst, "%(mnemonic)s", instMnem,
                false, false, false, false,
                _src1, _imm8, _dest, _srcSize, _destSize, _ext,
                %(op_class)s)
    {
        buildMe();
    }

    inline %(class_name)s::%(class_name)s(
            ExtMachInst machInst, const char * instMnem,
            bool isMicro, bool isDelayed, bool isFirst, bool isLast,
            InstRegIndex _src1, uint16_t _imm8, InstRegIndex _dest,
            uint8_t _srcSize, uint8_t _destSize, uint16_t _ext) :
        %(base_class)s(machInst, "%(mnemonic)s", instMnem,
                isMicro, isDelayed, isFirst, isLast,
                _src1, _imm8, _dest, _srcSize, _destSize, _ext,
                %(op_class)s)
    {
        buildMe();
    }
}};

let {{
    # Make these empty strings so that concatenating onto
    # them will always work.
    header_output = ""
    decoder_output = ""
    exec_output = ""

    immTemplates = (
            MediaOpImmDeclare,
            MediaOpImmConstructor,
            MediaOpExecute)

    regTemplates = (
            MediaOpRegDeclare,
            MediaOpRegConstructor,
            MediaOpExecute)

    class MediaOpMeta(type):
        def buildCppClasses(self, name, Name, suffix, code):

            # Globals to stick the output in
            global header_output
            global decoder_output
            global exec_output

            # If op2 is used anywhere, make register and immediate versions
            # of this code.
            matcher = re.compile("(?<!\\w)(?P<prefix>s?)op2(?P<typeQual>\\.\\w+)?")
            match = matcher.search(code)
            if match:
                typeQual = ""
                if match.group("typeQual"):
                    typeQual = match.group("typeQual")
                src2_name = "%spsrc2%s" % (match.group("prefix"), typeQual)
                self.buildCppClasses(name, Name, suffix,
                        matcher.sub(src2_name, code))
                self.buildCppClasses(name + "i", Name, suffix + "Imm",
                        matcher.sub("imm8", code))
                return

            base = "X86ISA::MediaOp"

            # If imm8 shows up in the code, use the immediate templates, if
            # not, hopefully the register ones will be correct.
            matcher = re.compile("(?<!\w)imm8(?!\w)")
            if matcher.search(code):
                base += "Imm"
                templates = immTemplates
            else:
                base += "Reg"
                templates = regTemplates

            # Get everything ready for the substitution
            iop = InstObjParams(name, Name + suffix, base, {"code" : code})

            # Generate the actual code (finally!)
            header_output += templates[0].subst(iop)
            decoder_output += templates[1].subst(iop)
            exec_output += templates[2].subst(iop)


        def __new__(mcls, Name, bases, dict):
            abstract = False
            name = Name.lower()
            if "abstract" in dict:
                abstract = dict['abstract']
                del dict['abstract']

            cls = super(MediaOpMeta, mcls).__new__(mcls, Name, bases, dict)
            if not abstract:
                cls.className = Name
                cls.base_mnemonic = name
                code = cls.code

                # Set up the C++ classes
                mcls.buildCppClasses(cls, name, Name, "", code)

                # Hook into the microassembler dict
                global microopClasses
                microopClasses[name] = cls

                # If op2 is used anywhere, make register and immediate versions
                # of this code.
                matcher = re.compile("op2(?P<typeQual>\\.\\w+)?")
                if matcher.search(code):
                    microopClasses[name + 'i'] = cls
            return cls


    class MediaOp(X86Microop):
        __metaclass__ = MediaOpMeta
        # This class itself doesn't act as a microop
        abstract = True

        def __init__(self, dest, src1, op2,
                size = None, destSize = None, srcSize = None, ext = None):
            self.dest = dest
            self.src1 = src1
            self.op2 = op2
            if size is not None:
                self.srcSize = size
                self.destSize = size
            if srcSize is not None:
                self.srcSize = srcSize
            if destSize is not None:
                self.destSize = destSize
            if self.srcSize is None:
                raise Exception, "Source size not set."
            if self.destSize is None:
                raise Exception, "Dest size not set."
            if ext is None:
                self.ext = 0
            else:
                self.ext = ext 

        def getAllocator(self, *microFlags):
            className = self.className
            if self.mnemonic == self.base_mnemonic + 'i':
                className += "Imm"
            allocator = '''new %(class_name)s(machInst, macrocodeBlock
                    %(flags)s, %(src1)s, %(op2)s, %(dest)s,
                    %(srcSize)s, %(destSize)s, %(ext)s)''' % {
                "class_name" : className,
                "flags" : self.microFlagsText(microFlags),
                "src1" : self.src1, "op2" : self.op2,
                "dest" : self.dest,
                "srcSize" : self.srcSize,
                "destSize" : self.destSize,
                "ext" : self.ext}
            return allocator

    class Mov2int(MediaOp):
        def __init__(self, dest, src, \
                size = None, destSize = None, srcSize = None, ext = None):
            super(Mov2int, self).__init__(dest, src,\
                    "InstRegIndex(0)", size, destSize, srcSize, ext)
        code = '''
            uint64_t fpSrcReg1 = bits(FpSrcReg1.uqw, srcSize * 8 - 1, 0);
            DestReg = merge(DestReg, fpSrcReg1, destSize);
        '''

    class Mov2fp(MediaOp):
        def __init__(self, dest, src, \
                size = None, destSize = None, srcSize = None, ext = None):
            super(Mov2fp, self).__init__(dest, src,\
                    "InstRegIndex(0)", size, destSize, srcSize, ext)
        code = '''
            uint64_t srcReg1 = pick(SrcReg1, 0, srcSize);
            FpDestReg.uqw =
                insertBits(FpDestReg.uqw, destSize * 8 - 1, 0, srcReg1);
        '''

    class Unpack(MediaOp):
        code = '''
            assert(srcSize == destSize);
            int size = destSize;
            int items = (sizeof(FloatRegBits) / size) / 2;
            int offset = ext ? items : 0;
            uint64_t result = 0;
            for (int i = 0; i < items; i++) {
                uint64_t pickedLow =
                    bits(FpSrcReg1.uqw, (i + offset + 1) * 8 * size - 1,
                                        (i + offset) * 8 * size);
                result = insertBits(result,
                                    (2 * i + 1) * 8 * size - 1,
                                    (2 * i + 0) * 8 * size,
                                    pickedLow);
                uint64_t pickedHigh =
                    bits(FpSrcReg2.uqw, (i + offset + 1) * 8 * size - 1,
                                        (i + offset) * 8 * size);
                result = insertBits(result,
                                    (2 * i + 2) * 8 * size - 1,
                                    (2 * i + 1) * 8 * size,
                                    pickedHigh);
            }
            FpDestReg.uqw = result;
        '''

    class Pack(MediaOp):
        code = '''
            assert(srcSize == destSize * 2);
            int items = (sizeof(FloatRegBits) / destSize);
            int destBits = destSize * 8;
            int srcBits = srcSize * 8;
            uint64_t result = 0;
            int i;
            for (i = 0; i < items / 2; i++) {
                uint64_t picked =
                    bits(FpSrcReg1.uqw, (i + 1) * srcBits - 1,
                                        (i + 0) * srcBits);
                unsigned signBit = bits(picked, srcBits - 1);
                uint64_t overflow = bits(picked, srcBits - 1, destBits - 1);

                // Handle saturation.
                if (signBit) {
                    if (overflow != mask(destBits - srcBits + 1)) {
                        if (ext & 0x1)
                            picked = (1 << (destBits - 1));
                        else
                            picked = 0;
                    }
                } else {
                    if (overflow != 0) {
                        if (ext & 0x1)
                            picked = mask(destBits - 1);
                        else
                            picked = mask(destBits);
                    }
                }
                result = insertBits(result,
                                    (i + 1) * destBits - 1,
                                    (i + 0) * destBits,
                                    picked);
            }
            for (;i < items; i++) {
                uint64_t picked =
                    bits(FpSrcReg2.uqw, (i - items + 1) * srcBits - 1,
                                        (i - items + 0) * srcBits);
                unsigned signBit = bits(picked, srcBits - 1);
                uint64_t overflow = bits(picked, srcBits - 1, destBits - 1);

                // Handle saturation.
                if (signBit) {
                    if (overflow != mask(destBits - srcBits + 1)) {
                        if (ext & 0x1)
                            picked = (1 << (destBits - 1));
                        else
                            picked = 0;
                    }
                } else {
                    if (overflow != 0) {
                        if (ext & 0x1)
                            picked = mask(destBits - 1);
                        else
                            picked = mask(destBits);
                    }
                }
                result = insertBits(result,
                                    (i + 1) * destBits - 1,
                                    (i + 0) * destBits,
                                    picked);
            }
            FpDestReg.uqw = result;
        '''

    class Mxor(MediaOp):
        def __init__(self, dest, src1, src2):
            super(Mxor, self).__init__(dest, src1, src2, 1)
        code = '''
            FpDestReg.uqw = FpSrcReg1.uqw ^ FpSrcReg2.uqw;
        '''

    class Mor(MediaOp):
        def __init__(self, dest, src1, src2):
            super(Mor, self).__init__(dest, src1, src2, 1)
        code = '''
            FpDestReg.uqw = FpSrcReg1.uqw | FpSrcReg2.uqw;
        '''

    class Mand(MediaOp):
        def __init__(self, dest, src1, src2):
            super(Mand, self).__init__(dest, src1, src2, 1)
        code = '''
            FpDestReg.uqw = FpSrcReg1.uqw & FpSrcReg2.uqw;
        '''

    class Mandn(MediaOp):
        def __init__(self, dest, src1, src2):
            super(Mandn, self).__init__(dest, src1, src2, 1)
        code = '''
            FpDestReg.uqw = ~FpSrcReg1.uqw & FpSrcReg2.uqw;
        '''

    class Mminf(MediaOp):
        code = '''
            union floatInt
            {
                float f;
                uint32_t i;
            };
            union doubleInt
            {
                double d;
                uint64_t i;
            };

            assert(srcSize == destSize);
            int size = srcSize;
            int sizeBits = size * 8;
            assert(srcSize == 4 || srcSize == 8);
            int items = (ext & 0x1) ? 1: (sizeof(FloatRegBits) / size);
            uint64_t result = FpDestReg.uqw;

            for (int i = 0; i < items; i++) {
                double arg1, arg2;
                int hiIndex = (i + 1) * sizeBits - 1;
                int loIndex = (i + 0) * sizeBits;
                uint64_t arg1Bits = bits(FpSrcReg1.uqw, hiIndex, loIndex);
                uint64_t arg2Bits = bits(FpSrcReg2.uqw, hiIndex, loIndex);

                if (size == 4) {
                    floatInt fi;
                    fi.i = arg1Bits;
                    arg1 = fi.f;
                    fi.i = arg2Bits;
                    arg2 = fi.f;
                } else {
                    doubleInt di;
                    di.i = arg1Bits;
                    arg1 = di.d;
                    di.i = arg2Bits;
                    arg2 = di.d;
                }

                if (arg1 < arg2) {
                    result = insertBits(result, hiIndex, loIndex, arg1Bits);
                } else {
                    result = insertBits(result, hiIndex, loIndex, arg2Bits);
                }
            }
            FpDestReg.uqw = result;
        '''

    class Mmaxf(MediaOp):
        code = '''
            union floatInt
            {
                float f;
                uint32_t i;
            };
            union doubleInt
            {
                double d;
                uint64_t i;
            };

            assert(srcSize == destSize);
            int size = srcSize;
            int sizeBits = size * 8;
            assert(srcSize == 4 || srcSize == 8);
            int items = (ext & 0x1) ? 1: (sizeof(FloatRegBits) / size);
            uint64_t result = FpDestReg.uqw;

            for (int i = 0; i < items; i++) {
                double arg1, arg2;
                int hiIndex = (i + 1) * sizeBits - 1;
                int loIndex = (i + 0) * sizeBits;
                uint64_t arg1Bits = bits(FpSrcReg1.uqw, hiIndex, loIndex);
                uint64_t arg2Bits = bits(FpSrcReg2.uqw, hiIndex, loIndex);

                if (size == 4) {
                    floatInt fi;
                    fi.i = arg1Bits;
                    arg1 = fi.f;
                    fi.i = arg2Bits;
                    arg2 = fi.f;
                } else {
                    doubleInt di;
                    di.i = arg1Bits;
                    arg1 = di.d;
                    di.i = arg2Bits;
                    arg2 = di.d;
                }

                if (arg1 > arg2) {
                    result = insertBits(result, hiIndex, loIndex, arg1Bits);
                } else {
                    result = insertBits(result, hiIndex, loIndex, arg2Bits);
                }
            }
            FpDestReg.uqw = result;
        '''

    class Msqrt(MediaOp):
        def __init__(self, dest, src, \
                size = None, destSize = None, srcSize = None, ext = None):
            super(Msqrt, self).__init__(dest, src,\
                    "InstRegIndex(0)", size, destSize, srcSize, ext)
        code = '''
            union floatInt
            {
                float f;
                uint32_t i;
            };
            union doubleInt
            {
                double d;
                uint64_t i;
            };

            assert(srcSize == destSize);
            int size = srcSize;
            int sizeBits = size * 8;
            assert(srcSize == 4 || srcSize == 8);
            int items = (ext & 0x1) ? 1: (sizeof(FloatRegBits) / size);
            uint64_t result = FpDestReg.uqw;

            for (int i = 0; i < items; i++) {
                int hiIndex = (i + 1) * sizeBits - 1;
                int loIndex = (i + 0) * sizeBits;
                uint64_t argBits = bits(FpSrcReg1.uqw, hiIndex, loIndex);

                if (size == 4) {
                    floatInt fi;
                    fi.i = argBits;
                    fi.f = sqrt(fi.f);
                    argBits = fi.i;
                } else {
                    doubleInt di;
                    di.i = argBits;
                    di.d = sqrt(di.d);
                    argBits = di.i;
                }
                result = insertBits(result, hiIndex, loIndex, argBits);
            }
            FpDestReg.uqw = result;
        '''

    class Maddf(MediaOp):
        code = '''
            union floatInt
            {
                float f;
                uint32_t i;
            };
            union doubleInt
            {
                double d;
                uint64_t i;
            };

            assert(srcSize == destSize);
            int size = srcSize;
            int sizeBits = size * 8;
            assert(srcSize == 4 || srcSize == 8);
            int items = (ext & 0x1) ? 1: (sizeof(FloatRegBits) / size);
            uint64_t result = FpDestReg.uqw;

            for (int i = 0; i < items; i++) {
                int hiIndex = (i + 1) * sizeBits - 1;
                int loIndex = (i + 0) * sizeBits;
                uint64_t arg1Bits = bits(FpSrcReg1.uqw, hiIndex, loIndex);
                uint64_t arg2Bits = bits(FpSrcReg2.uqw, hiIndex, loIndex);
                uint64_t resBits;

                if (size == 4) {
                    floatInt arg1, arg2, res;
                    arg1.i = arg1Bits;
                    arg2.i = arg2Bits;
                    res.f = arg1.f + arg2.f;
                    resBits = res.i;
                } else {
                    doubleInt arg1, arg2, res;
                    arg1.i = arg1Bits;
                    arg2.i = arg2Bits;
                    res.d = arg1.d + arg2.d;
                    resBits = res.i;
                }

                result = insertBits(result, hiIndex, loIndex, resBits);
            }
            FpDestReg.uqw = result;
        '''

    class Msubf(MediaOp):
        code = '''
            union floatInt
            {
                float f;
                uint32_t i;
            };
            union doubleInt
            {
                double d;
                uint64_t i;
            };

            assert(srcSize == destSize);
            int size = srcSize;
            int sizeBits = size * 8;
            assert(srcSize == 4 || srcSize == 8);
            int items = (ext & 0x1) ? 1: (sizeof(FloatRegBits) / size);
            uint64_t result = FpDestReg.uqw;

            for (int i = 0; i < items; i++) {
                int hiIndex = (i + 1) * sizeBits - 1;
                int loIndex = (i + 0) * sizeBits;
                uint64_t arg1Bits = bits(FpSrcReg1.uqw, hiIndex, loIndex);
                uint64_t arg2Bits = bits(FpSrcReg2.uqw, hiIndex, loIndex);
                uint64_t resBits;

                if (size == 4) {
                    floatInt arg1, arg2, res;
                    arg1.i = arg1Bits;
                    arg2.i = arg2Bits;
                    res.f = arg1.f - arg2.f;
                    resBits = res.i;
                } else {
                    doubleInt arg1, arg2, res;
                    arg1.i = arg1Bits;
                    arg2.i = arg2Bits;
                    res.d = arg1.d - arg2.d;
                    resBits = res.i;
                }

                result = insertBits(result, hiIndex, loIndex, resBits);
            }
            FpDestReg.uqw = result;
        '''

    class Mmulf(MediaOp):
        code = '''
            union floatInt
            {
                float f;
                uint32_t i;
            };
            union doubleInt
            {
                double d;
                uint64_t i;
            };

            assert(srcSize == destSize);
            int size = srcSize;
            int sizeBits = size * 8;
            assert(srcSize == 4 || srcSize == 8);
            int items = (ext & 0x1) ? 1: (sizeof(FloatRegBits) / size);
            uint64_t result = FpDestReg.uqw;

            for (int i = 0; i < items; i++) {
                int hiIndex = (i + 1) * sizeBits - 1;
                int loIndex = (i + 0) * sizeBits;
                uint64_t arg1Bits = bits(FpSrcReg1.uqw, hiIndex, loIndex);
                uint64_t arg2Bits = bits(FpSrcReg2.uqw, hiIndex, loIndex);
                uint64_t resBits;

                if (size == 4) {
                    floatInt arg1, arg2, res;
                    arg1.i = arg1Bits;
                    arg2.i = arg2Bits;
                    res.f = arg1.f * arg2.f;
                    resBits = res.i;
                } else {
                    doubleInt arg1, arg2, res;
                    arg1.i = arg1Bits;
                    arg2.i = arg2Bits;
                    res.d = arg1.d * arg2.d;
                    resBits = res.i;
                }

                result = insertBits(result, hiIndex, loIndex, resBits);
            }
            FpDestReg.uqw = result;
        '''

    class Mdivf(MediaOp):
        code = '''
            union floatInt
            {
                float f;
                uint32_t i;
            };
            union doubleInt
            {
                double d;
                uint64_t i;
            };

            assert(srcSize == destSize);
            int size = srcSize;
            int sizeBits = size * 8;
            assert(srcSize == 4 || srcSize == 8);
            int items = (ext & 0x1) ? 1: (sizeof(FloatRegBits) / size);
            uint64_t result = FpDestReg.uqw;

            for (int i = 0; i < items; i++) {
                int hiIndex = (i + 1) * sizeBits - 1;
                int loIndex = (i + 0) * sizeBits;
                uint64_t arg1Bits = bits(FpSrcReg1.uqw, hiIndex, loIndex);
                uint64_t arg2Bits = bits(FpSrcReg2.uqw, hiIndex, loIndex);
                uint64_t resBits;

                if (size == 4) {
                    floatInt arg1, arg2, res;
                    arg1.i = arg1Bits;
                    arg2.i = arg2Bits;
                    res.f = arg1.f / arg2.f;
                    resBits = res.i;
                } else {
                    doubleInt arg1, arg2, res;
                    arg1.i = arg1Bits;
                    arg2.i = arg2Bits;
                    res.d = arg1.d / arg2.d;
                    resBits = res.i;
                }

                result = insertBits(result, hiIndex, loIndex, resBits);
            }
            FpDestReg.uqw = result;
        '''

    class Cvti2f(MediaOp):
        def __init__(self, dest, src, \
                size = None, destSize = None, srcSize = None, ext = None):
            super(Cvti2f, self).__init__(dest, src,\
                    "InstRegIndex(0)", size, destSize, srcSize, ext)
        code = '''
            union floatInt
            {
                float f;
                uint32_t i;
            };
            union doubleInt
            {
                double d;
                uint64_t i;
            };

            assert(destSize == 4 || destSize == 8);
            assert(srcSize == 4 || srcSize == 8);
            int srcSizeBits = srcSize * 8;
            int destSizeBits = destSize * 8;
            int items;
            int srcStart = 0;
            int destStart = 0;
            if (srcSize == 2 * destSize) {
                items = (ext & 0x1) ? 1: sizeof(FloatRegBits) / srcSize;
                if (ext & 0x2)
                    destStart = destSizeBits * items;
            } else if (destSize == 2 * srcSize) {
                items = (ext & 0x1) ? 1: sizeof(FloatRegBits) / destSize;
                if (ext & 0x2)
                    srcStart = srcSizeBits * items;
            } else {
                items = (ext & 0x1) ? 1: sizeof(FloatRegBits) / destSize;
            }
            uint64_t result = FpDestReg.uqw;

            for (int i = 0; i < items; i++) {
                int srcHiIndex = srcStart + (i + 1) * srcSizeBits - 1;
                int srcLoIndex = srcStart + (i + 0) * srcSizeBits;
                uint64_t argBits = bits(FpSrcReg1.uqw, srcHiIndex, srcLoIndex);
                int64_t sArg = argBits | (0 - (argBits & (1 << srcHiIndex)));
                double arg = sArg;

                if (destSize == 4) {
                    floatInt fi;
                    fi.f = arg;
                    argBits = fi.i;
                } else {
                    doubleInt di;
                    di.d = arg;
                    argBits = di.i;
                }
                int destHiIndex = destStart + (i + 1) * destSizeBits - 1;
                int destLoIndex = destStart + (i + 0) * destSizeBits;
                result = insertBits(result, destHiIndex, destLoIndex, argBits);
            }
            FpDestReg.uqw = result;
        '''

    class Cvtf2f(MediaOp):
        def __init__(self, dest, src, \
                size = None, destSize = None, srcSize = None, ext = None):
            super(Cvtf2f, self).__init__(dest, src,\
                    "InstRegIndex(0)", size, destSize, srcSize, ext)
        code = '''
            union floatInt
            {
                float f;
                uint32_t i;
            };
            union doubleInt
            {
                double d;
                uint64_t i;
            };

            assert(destSize == 4 || destSize == 8);
            assert(srcSize == 4 || srcSize == 8);
            int srcSizeBits = srcSize * 8;
            int destSizeBits = destSize * 8;
            int items;
            int srcStart = 0;
            int destStart = 0;
            if (srcSize == 2 * destSize) {
                items = (ext & 0x1) ? 1: sizeof(FloatRegBits) / srcSize;
                if (ext & 0x2)
                    destStart = destSizeBits * items;
            } else if (destSize == 2 * srcSize) {
                items = (ext & 0x1) ? 1: sizeof(FloatRegBits) / destSize;
                if (ext & 0x2)
                    srcStart = srcSizeBits * items;
            } else {
                items = (ext & 0x1) ? 1: sizeof(FloatRegBits) / destSize;
            }
            uint64_t result = FpDestReg.uqw;

            for (int i = 0; i < items; i++) {
                int srcHiIndex = srcStart + (i + 1) * srcSizeBits - 1;
                int srcLoIndex = srcStart + (i + 0) * srcSizeBits;
                uint64_t argBits = bits(FpSrcReg1.uqw, srcHiIndex, srcLoIndex);
                double arg;

                if (srcSize == 4) {
                    floatInt fi;
                    fi.i = argBits;
                    arg = fi.f;
                } else {
                    doubleInt di;
                    di.i = argBits;
                    arg = di.d;
                }
                if (destSize == 4) {
                    floatInt fi;
                    fi.f = arg;
                    argBits = fi.i;
                } else {
                    doubleInt di;
                    di.d = arg;
                    argBits = di.i;
                }
                int destHiIndex = destStart + (i + 1) * destSizeBits - 1;
                int destLoIndex = destStart + (i + 0) * destSizeBits;
                result = insertBits(result, destHiIndex, destLoIndex, argBits);
            }
            FpDestReg.uqw = result;
        '''

    class Mcmpi2r(MediaOp):
        code = '''
            union floatInt
            {
                float f;
                uint32_t i;
            };
            union doubleInt
            {
                double d;
                uint64_t i;
            };

            assert(srcSize == destSize);
            int size = srcSize;
            int sizeBits = size * 8;
            int items = (ext & 0x1) ? 1: (sizeof(FloatRegBits) / size);
            uint64_t result = FpDestReg.uqw;

            for (int i = 0; i < items; i++) {
                int hiIndex = (i + 1) * sizeBits - 1;
                int loIndex = (i + 0) * sizeBits;
                uint64_t arg1Bits = bits(FpSrcReg1.uqw, hiIndex, loIndex);
                int64_t arg1 = arg1Bits |
                    (0 - (arg1Bits & (1 << (sizeBits - 1))));
                uint64_t arg2Bits = bits(FpSrcReg2.uqw, hiIndex, loIndex);
                int64_t arg2 = arg2Bits |
                    (0 - (arg2Bits & (1 << (sizeBits - 1))));

                uint64_t resBits = 0;
                if ((ext & 0x2) == 0 && arg1 == arg2 ||
                        (ext & 0x2) == 0x2 && arg1 > arg2)
                    resBits = mask(sizeBits);

                result = insertBits(result, hiIndex, loIndex, resBits);
            }
            FpDestReg.uqw = result;
        '''
}};