| // -*- mode:c++ -*- |
| |
| // Copyright (c) 2007 The Hewlett-Packard Development Company |
| // All rights reserved. |
| // |
| // Redistribution and use of this software in source and binary forms, |
| // with or without modification, are permitted provided that the |
| // following conditions are met: |
| // |
| // The software must be used only for Non-Commercial Use which means any |
| // use which is NOT directed to receiving any direct monetary |
| // compensation for, or commercial advantage from such use. Illustrative |
| // examples of non-commercial use are academic research, personal study, |
| // teaching, education and corporate research & development. |
| // Illustrative examples of commercial use are distributing products for |
| // commercial advantage and providing services using the software for |
| // commercial advantage. |
| // |
| // If you wish to use this software or functionality therein that may be |
| // covered by patents for commercial use, please contact: |
| // Director of Intellectual Property Licensing |
| // Office of Strategy and Technology |
| // Hewlett-Packard Company |
| // 1501 Page Mill Road |
| // Palo Alto, California 94304 |
| // |
| // 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 HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its |
| // contributors may be used to endorse or promote products derived from |
| // this software without specific prior written permission. No right of |
| // sublicense is granted herewith. Derivatives of the software and |
| // output created using the software may be prepared, but only for |
| // Non-Commercial Uses. Derivatives of the software may be shared with |
| // others provided: (i) the others agree to abide by the list of |
| // conditions herein which includes the Non-Commercial Use restrictions; |
| // and (ii) such Derivatives of the software include the above copyright |
| // notice to acknowledge the contribution from this software where |
| // applicable, this list of conditions and the disclaimer below. |
| // |
| // 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 |
| |
| ////////////////////////////////////////////////////////////////////////////// |
| // |
| // Architecture independent |
| // |
| |
| // Execute method for macroops. |
| def template MacroExecPanic {{ |
| Fault execute(%(CPU_exec_context)s *, Trace::InstRecord *) const |
| { |
| panic("Tried to execute macroop directly!"); |
| return NoFault; |
| } |
| }}; |
| |
| output header {{ |
| |
| // Base class for combinationally generated macroops |
| class Macroop : public StaticInst |
| { |
| protected: |
| const uint32_t numMicroops; |
| |
| //Constructor. |
| Macroop(const char *mnem, ExtMachInst _machInst, |
| uint32_t _numMicroops) |
| : StaticInst(mnem, _machInst, No_OpClass), |
| numMicroops(_numMicroops) |
| { |
| assert(numMicroops); |
| microops = new StaticInstPtr[numMicroops]; |
| flags[IsMacroop] = true; |
| } |
| |
| ~Macroop() |
| { |
| delete [] microops; |
| } |
| |
| StaticInstPtr * microops; |
| |
| StaticInstPtr fetchMicroop(MicroPC microPC) |
| { |
| assert(microPC < numMicroops); |
| return microops[microPC]; |
| } |
| |
| std::string generateDisassembly(Addr pc, |
| const SymbolTable *symtab) const |
| { |
| return mnemonic; |
| } |
| |
| %(MacroExecPanic)s |
| }; |
| }}; |
| |
| ////////////////////////////////////////////////////////////////////////////// |
| // |
| // X86 specific |
| // |
| ////////////////////////////////////////////////////////////////////////////// |
| |
| // Basic instruction class declaration template. |
| def template MacroDeclare {{ |
| namespace X86Macroop |
| { |
| /** |
| * Static instruction class for "%(mnemonic)s". |
| */ |
| class %(class_name)s : public %(base_class)s |
| { |
| private: |
| %(declareLabels)s |
| public: |
| // Constructor. |
| %(class_name)s(ExtMachInst machInst, X86ISA::EmulEnv env); |
| }; |
| }; |
| }}; |
| |
| // Basic instruction class constructor template. |
| def template MacroConstructor {{ |
| inline X86Macroop::%(class_name)s::%(class_name)s( |
| ExtMachInst machInst, EmulEnv env) |
| : %(base_class)s("%(mnemonic)s", machInst, %(num_microops)s) |
| { |
| %(adjust_env)s; |
| %(adjust_imm)s; |
| %(adjust_disp)s; |
| %(do_modrm)s; |
| %(constructor)s; |
| //alloc_microops is the code that sets up the microops |
| //array in the parent class. |
| %(alloc_microops)s; |
| } |
| }}; |
| |
| let {{ |
| from micro_asm import Combinational_Macroop, Rom_Macroop |
| class X86Macroop(Combinational_Macroop): |
| def add_microop(self, mnemonic, microop): |
| microop.mnemonic = mnemonic |
| microop.micropc = len(self.microops) |
| self.microops.append(microop) |
| def setAdjustEnv(self, val): |
| self.adjust_env = val |
| def adjustImm(self, val): |
| self.adjust_imm += val |
| def adjustDisp(self, val): |
| self.adjust_disp += val |
| def __init__(self, name): |
| super(X86Macroop, self).__init__(name) |
| self.directives = { |
| "adjust_env" : self.setAdjustEnv, |
| "adjust_imm" : self.adjustImm, |
| "adjust_disp" : self.adjustDisp |
| } |
| self.declared = False |
| self.adjust_env = "" |
| self.doModRM = "" |
| self.adjust_imm = ''' |
| uint64_t adjustedImm = IMMEDIATE; |
| //This is to pacify gcc in case the immediate isn't used. |
| adjustedImm = adjustedImm; |
| ''' |
| self.adjust_disp = ''' |
| uint64_t adjustedDisp = DISPLACEMENT; |
| //This is to pacify gcc in case the displacement isn't used. |
| adjustedDisp = adjustedDisp; |
| ''' |
| def getAllocator(self, env): |
| return "new X86Macroop::%s(machInst, %s)" % (self.name, env.getAllocator()) |
| def getDeclaration(self): |
| #FIXME This first parameter should be the mnemonic. I need to |
| #write some code which pulls that out |
| declareLabels = "" |
| for (label, microop) in self.labels.items(): |
| declareLabels += "const static uint64_t label_%s = %d;\n" \ |
| % (label, microop.micropc) |
| iop = InstObjParams(self.name, self.name, "Macroop", |
| {"code" : "", |
| "declareLabels" : declareLabels |
| }) |
| return MacroDeclare.subst(iop); |
| def getDefinition(self): |
| #FIXME This first parameter should be the mnemonic. I need to |
| #write some code which pulls that out |
| numMicroops = len(self.microops) |
| allocMicroops = '' |
| micropc = 0 |
| for op in self.microops: |
| allocMicroops += \ |
| "microops[%d] = %s;\n" % \ |
| (micropc, op.getAllocator(True, False, |
| micropc == 0, |
| micropc == numMicroops - 1)) |
| micropc += 1 |
| iop = InstObjParams(self.name, self.name, "Macroop", |
| {"code" : "", "num_microops" : numMicroops, |
| "alloc_microops" : allocMicroops, |
| "adjust_env" : self.adjust_env, |
| "adjust_imm" : self.adjust_imm, |
| "adjust_disp" : self.adjust_disp, |
| "do_modrm" : self.doModRM}) |
| return MacroConstructor.subst(iop); |
| }}; |
| |
| let {{ |
| class EmulEnv(object): |
| def __init__(self): |
| self.reg = "0" |
| self.regUsed = False |
| self.regm = "0" |
| self.regmUsed = False |
| self.seg = "SEGMENT_REG_DS" |
| self.size = None |
| self.addressSize = "ADDRSIZE" |
| self.dataSize = "OPSIZE" |
| self.stackSize = "STACKSIZE" |
| self.doModRM = False |
| |
| def getAllocator(self): |
| if self.size == 'b': |
| self.dataSize = 1 |
| elif self.size == 'd': |
| self.dataSize = 4 |
| #This is for "double plus" which is normally a double word unless |
| #the REX W bit is set, in which case it's a quad word. It's used |
| #for some SSE instructions. |
| elif self.size == 'dp': |
| self.dataSize = "(REX_W ? 8 : 4)" |
| elif self.size == 'q': |
| self.dataSize = 8 |
| elif self.size == 'v': |
| self.dataSize = "OPSIZE" |
| elif self.size == 'w': |
| self.dataSize = 2 |
| elif self.size == 'z': |
| self.dataSize = "((OPSIZE == 8) ? 4 : OPSIZE)" |
| elif self.size: |
| raise Exception, "Unrecognized size type %s!" % self.size |
| return '''EmulEnv(%(reg)s, |
| %(regm)s, |
| %(dataSize)s, |
| %(addressSize)s, |
| %(stackSize)s)''' % \ |
| self.__dict__ |
| |
| def addReg(self, reg): |
| if not self.regUsed: |
| self.reg = reg |
| self.regUsed = True |
| elif not self.regmUsed: |
| self.regm = reg |
| self.regmUsed = True |
| else: |
| raise Exception, "EmulEnv is out of register specialization spots." |
| def setSize(self, size): |
| if not self.size: |
| self.size = size |
| else: |
| if self.size != size: |
| raise Exception, "Conflicting register sizes %s and %s!" %\ |
| (self.size, size) |
| }}; |
| |
| let {{ |
| doModRMString = "env.doModRM(machInst);\n" |
| def genMacroop(Name, env): |
| blocks = OutputBlocks() |
| if not macroopDict.has_key(Name): |
| raise Exception, "Unrecognized instruction: %s" % Name |
| macroop = macroopDict[Name] |
| if not macroop.declared: |
| if env.doModRM: |
| macroop.doModRM = doModRMString |
| blocks.header_output = macroop.getDeclaration() |
| blocks.decoder_output = macroop.getDefinition() |
| macroop.declared = True |
| blocks.decode_block = "return %s;\n" % macroop.getAllocator(env) |
| return blocks |
| }}; |