/// 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("(?s?)op2(?P\\.\\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+)?") 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; ''' }};